引言
在软件开发中,我们经常会遇到这样的困境:业务逻辑与技术细节紧密耦合,修改数据库层会影响领域逻辑,换一个Web框架需要大量重构代码。这种强耦合让系统变得难以维护、难以测试、难以扩展。
洋葱架构(Onion Architecture) 提供了一种优雅的解决方案。它由Jeffrey Palermo在2008年提出,核心思想是将业务逻辑置于架构的中心,让外部依赖层层包裹。
什么是洋葱架构?
洋葱架构是一种分层架构模式,它的核心原则是:
依赖方向只能指向内核,越往外层越脆弱
架构分层
┌─────────────────────────────────────┐
│ 基础设施层 (Infrastructure) │ ← 最外层:Web、数据库、消息队列
├─────────────────────────────────────┤
│ 应用层 (Application) │ ← 用例 orchestration
├─────────────────────────────────────┤
│ 领域层 (Domain) │ ← 核心业务逻辑、实体、值对象
├─────────────────────────────────────┤
│ 核心层 (Core) │ ← 最内核:领域接口、领域事件
└─────────────────────────────────────┘
核心原则
- 依赖倒置:外层依赖内层,内层不关心外层实现
- 领域中心:核心业务逻辑不受技术栈影响
- 可替换性:外层组件可以随时替换而不影响核心
- 可测试性:核心业务逻辑可以独立于外部组件测试
洋葱架构的四大层级
1. 核心层(Core Domain)
这是架构的最内核,包含:
- 领域接口(Ports):定义业务能力的抽象接口
- 领域实体(Entities):核心业务对象
- 值对象(Value Objects):不可变的业务概念
- 领域事件(Domain Events):业务状态变化
# 核心层示例 - Python
from abc import ABC, abstractmethod
from dataclasses import dataclass
# 领域实体
@dataclass
class Order:
order_id: str
customer_id: str
total_amount: float
status: str
# 领域接口 (Ports)
class OrderRepository(ABC):
@abstractmethod
def save(self, order: Order) -> Order:
pass
@abstractmethod
def find_by_id(self, order_id: str) -> Order:
pass
2. 领域层(Domain Services)
包含业务逻辑,但不依赖任何外部技术:
# 领域层示例
class OrderDomainService:
def __init__(self, order_repository: OrderRepository):
self._repository = order_repository
def create_order(self, customer_id: str, items: list) -> Order:
if not items:
raise ValueError("订单至少需要一个商品")
total = sum(item.price * item.quantity for item in items)
order = Order(
order_id=self._generate_order_id(),
customer_id=customer_id,
total_amount=total,
status="pending"
)
return self._repository.save(order)
3. 应用层(Application Services)
处理用例编排,协调领域服务:
# 应用层示例
class CreateOrderUseCase:
def __init__(
self,
order_service: OrderDomainService,
notification: NotificationService
):
self._order_service = order_service
self._notification = notification
def execute(self, customer_id: str, items: list) -> Order:
order = self._order_service.create_order(customer_id, items)
self._notification.send(
recipient=customer_id,
message=f"订单 {order.order_id} 已创建"
)
return order
4. 基础设施层(Infrastructure)
实现核心接口的具体技术:
# 基础设施层示例
class SQLiteOrderRepository(OrderRepository):
def __init__(self, db_connection):
self._db = db_connection
def save(self, order: Order) -> Order:
self._db.execute(
"INSERT INTO orders VALUES (?, ?, ?, ?)",
[order.order_id, order.customer_id,
order.total_amount, order.status]
)
return order
依赖注入:连接各层的桥梁
# 依赖注入配置
def create_order_module() -> CreateOrderUseCase:
db = SQLiteConnection("production.db")
repository = SQLiteOrderRepository(db)
notification = EmailNotification()
domain_service = OrderDomainService(repository)
return CreateOrderUseCase(domain_service, notification)
依赖注入的优势
| 优势 | 说明 |
|---|---|
| 解耦 | 业务逻辑与具体实现分离 |
| 可测试 | 轻松替换为 Mock 对象 |
| 可替换 | 换数据库、换框架只需改配置 |
洋葱架构 vs 其他架构
与 MVC 对比
| 特性 | MVC | 洋葱架构 |
|---|---|---|
| 业务逻辑位置 | Controller | 领域层 |
| 依赖方向 | 混乱 | 单向内聚 |
| 测试难度 | 困难 | 简单 |
| 适用场景 | 小型项目 | 中大型项目 |
与六边形架构对比
两者非常相似,洋葱架构可以看作六边形架构的演进版本。
何时使用洋葱架构?
适合使用
- 中大型项目:业务逻辑复杂,需要清晰分层
- 长期维护项目:需要良好的可扩展性和可测试性
- 技术变更频繁:可能需要切换数据库、框架
不适合使用
- 小型简单项目:过度设计,增加复杂度
- 快速原型验证:不需要完整架构
总结
洋葱架构不仅仅是一种技术方案,更是一种设计思维:
- 让业务逻辑成为核心:技术服务于业务,而非相反
- 依赖方向清晰:内层不关心外层实现
- 可测试、可维护:降低长期维护成本
- 适应变化:轻松应对技术栈更新
掌握洋葱架构,你将能够构建出更稳健、更可维护的企业级应用!
Top comments (0)