精选文章

26. 组件化

2020-05-27 · 组件化

26. 组件化

组件化的目标是“模块边界清晰、依赖可替换、功能可复用”。下面给出一套可落地的拆分方式。

一、模块分层

  • Core:网络、存储、工具
  • Features:业务模块
  • UI:通用组件

结构示例:

App
├─ Core
├─ Network
├─ Storage
├─ Features
│  ├─ Home
│  ├─ Profile
└─ UIComponents

二、SPM 本地包

Package.swift 示例:

// swift-tools-version:5.7
import PackageDescription

let package = Package(
    name: "Features",
    platforms: [.iOS(.v13)],
    products: [
        .library(name: "ProfileFeature", targets: ["ProfileFeature"])
    ],
    targets: [
        .target(name: "ProfileFeature", dependencies: ["Core"]),
        .target(name: "Core")
    ]
)

三、对外暴露入口

只暴露工厂方法,不暴露内部实现。

public struct ProfileFeature {
    public static func makeRoot(userID: Int, service: UserService) -> UIViewController {
        let vm = ProfileViewModel(userID: userID, service: service)
        return ProfileViewController(viewModel: vm)
    }
}

四、协议解耦依赖

public protocol UserService {
    func fetch(userID: Int, completion: @escaping (Result<User, Error>) -> Void)
}

final class RemoteUserService: UserService {
    func fetch(userID: Int, completion: @escaping (Result<User, Error>) -> Void) {
        // 网络请求实现
    }
}

业务模块只依赖协议,不依赖具体实现。

五、依赖注入

final class AppContainer {
    let userService: UserService

    init() {
        userService = RemoteUserService()
    }

    func makeProfile(userID: Int) -> UIViewController {
        ProfileFeature.makeRoot(userID: userID, service: userService)
    }
}

六、资源与 Bundle

SPM 资源建议放在模块内,使用 Bundle.module 访问:

let image = UIImage(named: "avatar", in: .module, compatibleWith: nil)

七、避免循环依赖

  • 业务模块只能依赖 Core/UI
  • Core 不依赖任何业务模块
  • 依赖方向单向

组件化不是堆模块数量,而是让每个模块职责稳定、边界清晰。

JJ

作者简介

专注于内容创作、产品策略与设计实践。欢迎交流合作。

上一篇 下一篇