DEV Community

架构师小白
架构师小白

Posted on

洋葱架构完全指南:构建稳健、可维护的企业级应用

引言

在软件开发中,我们经常会遇到这样的困境:业务逻辑与技术细节紧密耦合,修改数据库层会影响领域逻辑,换一个Web框架需要大量重构代码。这种强耦合让系统变得难以维护、难以测试、难以扩展。

洋葱架构(Onion Architecture) 提供了一种优雅的解决方案。它由Jeffrey Palermo在2008年提出,核心思想是将业务逻辑置于架构的中心,让外部依赖层层包裹。


什么是洋葱架构?

洋葱架构是一种分层架构模式,它的核心原则是:

依赖方向只能指向内核,越往外层越脆弱

架构分层

┌─────────────────────────────────────┐
│         基础设施层 (Infrastructure)  │  ← 最外层:Web、数据库、消息队列
├─────────────────────────────────────┤
│         应用层 (Application)         │  ← 用例 orchestration
├─────────────────────────────────────┤
│           领域层 (Domain)           │  ← 核心业务逻辑、实体、值对象
├─────────────────────────────────────┤
│         核心层 (Core)              │  ← 最内核:领域接口、领域事件
└─────────────────────────────────────┘
Enter fullscreen mode Exit fullscreen mode

核心原则

  1. 依赖倒置:外层依赖内层,内层不关心外层实现
  2. 领域中心:核心业务逻辑不受技术栈影响
  3. 可替换性:外层组件可以随时替换而不影响核心
  4. 可测试性:核心业务逻辑可以独立于外部组件测试

洋葱架构的四大层级

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
Enter fullscreen mode Exit fullscreen mode

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)
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

依赖注入:连接各层的桥梁

# 依赖注入配置
def create_order_module() -> CreateOrderUseCase:
    db = SQLiteConnection("production.db")
    repository = SQLiteOrderRepository(db)
    notification = EmailNotification()
    domain_service = OrderDomainService(repository)
    return CreateOrderUseCase(domain_service, notification)
Enter fullscreen mode Exit fullscreen mode

依赖注入的优势

优势 说明
解耦 业务逻辑与具体实现分离
可测试 轻松替换为 Mock 对象
可替换 换数据库、换框架只需改配置

洋葱架构 vs 其他架构

与 MVC 对比

特性 MVC 洋葱架构
业务逻辑位置 Controller 领域层
依赖方向 混乱 单向内聚
测试难度 困难 简单
适用场景 小型项目 中大型项目

与六边形架构对比

两者非常相似,洋葱架构可以看作六边形架构的演进版本。


何时使用洋葱架构?

适合使用

  • 中大型项目:业务逻辑复杂,需要清晰分层
  • 长期维护项目:需要良好的可扩展性和可测试性
  • 技术变更频繁:可能需要切换数据库、框架

不适合使用

  • 小型简单项目:过度设计,增加复杂度
  • 快速原型验证:不需要完整架构

总结

洋葱架构不仅仅是一种技术方案,更是一种设计思维:

  1. 让业务逻辑成为核心:技术服务于业务,而非相反
  2. 依赖方向清晰:内层不关心外层实现
  3. 可测试、可维护:降低长期维护成本
  4. 适应变化:轻松应对技术栈更新

掌握洋葱架构,你将能够构建出更稳健、更可维护的企业级应用!

Top comments (0)