Swift中的六边形架构:无依赖的纯净逻辑

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

当MVVM和MVC不再奏效,测试变成噩梦时



您是否曾经编写过一个Swift应用,半年后添加一个新功能却破坏了其他三个功能,而测试因为数据库从Core Data换成Realm而不得不完全重写?如果是这样,您并不孤单。经典的分层架构(MVC、MVVM)在项目初期运行良好,但随着项目增长会变成一团“乱麻”。



我将向您展示Hexagonal架构(也称为Ports & Adapters)——一种源自Java和DDD世界的方法,但非常适合Swift。我们将通过真实示例来解析它,而不是抽象的“User”和“Manager”。您将看到如何将业务逻辑与数据库、UI和网络分离,以便在不触及应用核心的情况下更换它们。



这不是又一个理论——这是您今天就可以在自己的项目中应用的实践。



什么是Hexagonal架构?简单来说



想象一个六边形(因此得名)。中心是您纯净的业务逻辑(领域)。边缘是端口(接口),外部世界通过它们与核心通信。适配器是具体的实现:数据库、API、UI、文件系统。



主要规则是:核心对外部世界一无所知。它不知道UIKit、URLSession或Core Data。它只知道自己的接口(端口)。



生活中的例子:想象一个在线商店。核心知道有“购物车”和“下订单”。它不在乎数据来自哪里——来自WebSocket、本地JSON还是键盘。适配器连接到端口,将外部信号转换为领域命令。



为什么应该在Swift项目中使用它?



  • 可测试性——您可以在没有真实数据库和网络的情况下测试领域。只需用模拟对象替换适配器。
  • 灵活性——想从Firebase切换到自己的服务器?只需更换一个适配器,而不是半个应用。
  • 可读性——业务逻辑不会分散在ViewController中。它集中在一个地方。
  • 框架无关性——您的核心不导入UIKit、Combine或Alamofire。


Swift中Hexagonal架构的项目结构



让我们直接进入代码。假设我们正在编写一个任务管理应用(Todolist)。文件夹结构如下:



App/├── Domain/│   ├── Entity/│   │   └── Task.swift│   ├── UseCase/│   │   └── CreateTaskUseCase.swift│   └── Port/│       ├── TaskRepository.swift│       └── TaskOutputPort.swift├── Adapter/│   ├── Persistence/│   │   └── CoreDataTaskRepository.swift│   ├── Network/│   │   └── APITaskRepository.swift│   └── Presentation/│       └── TaskListViewModel.swift└── Main/    └── AppDelegate.swift


请注意:Domain除了Foundation之外不导入任何东西。Adapter可以导入CoreData、UIKit、Alamofire——任何东西。



步骤1:领域实体和端口



我们从最重要的部分开始——领域模型。这是一个描述业务实体的struct或enum。没有NSManagedObject,没有Codable。



// Domain/Entity/Task.swiftstruct Task {    let id: UUID    var title: String    var isCompleted: Bool    let createdAt: Date}


现在定义仓库端口(输出端口)。这是一个描述如何保存和加载任务的协议。



// Domain/Port/TaskRepository.swiftprotocol TaskRepository {    func fetchAll() async throws -> [Task]    func save(task: Task) async throws    func delete(taskID: UUID) async throws}


以及输入端口——外部世界(UI、API)通过它与核心交互。通常这是一个UseCase。



// Domain/Us                

博客

书籍推荐