深入解析:iOS 组件化:模块拆分、依赖反转、解耦实践

为什么需要组件化

单体架构的痛点

┌─────────────────────────────────────────────────────────┐
│                      单体应用架构                         │
├─────────────────────────────────────────────────────────┤
│  ┌─────────┐  ┌─────────┐  ┌─────────┐  ┌─────────┐    │
│  │  首页   │←→│  购物车  │←→│  订单   │←→│  我的   │    │
│  └────┬────┘  └────┬────┘  └────┬────┘  └────┬────┘    │
│       │            │            │            │          │
│       └────────────┴─────┬──────┴────────────┘          │
│                          ↓                              │
│  ┌─────────────────────────────────────────────────┐   │
│  │              公共代码 & 工具类                    │   │
│  │   (网络层、数据库、工具类、基础UI 全部耦合在一起)   │   │
│  └─────────────────────────────────────────────────┘   │
└─────────────────────────────────────────────────────────┘
问题:
❌ 编译时间长(修改一行代码需全量编译)
❌ 代码冲突频繁(多人协作噩梦)
❌ 业务边界模糊(功能交叉,职责不清)
❌ 无法独立测试(牵一发动全身)
❌ 技术债务累积(代码腐化严重)

组件化目标

┌─────────────────────────────────────────────────────────┐
│                      组件化架构                          │
├─────────────────────────────────────────────────────────┤
│  独立开发    │    独立测试    │   独立发布    │  快速编译  │
├─────────────────────────────────────────────────────────┤
│                                                         │
│   ┌─────────┐   ┌─────────┐   ┌─────────┐              │
│   │ 首页组件 │   │ 购物车组件│   │ 订单组件 │   业务层    │
│   └────┬────┘   └────┬────┘   └────┬────┘              │
│        │             │             │                    │
│   ─────┴─────────────┴─────────────┴─────               │
│                      ↓                                  │
│   ┌─────────────────────────────────────┐              │
│   │           组件通信中间件             │   中间层     │
│   └─────────────────────────────────────┘              │
│                      ↓                                  │
│   ┌────────┐  ┌────────┐  ┌────────┐                   │
│   │ 网络库 │  │ 数据库 │  │ 工具库 │      基础层       │
│   └────────┘  └────────┘  └────────┘                   │
└─────────────────────────────────────────────────────────┘

组件化基础概念

组件分类

/*
组件分层金字塔
┌──────────────┐
│   壳工程      │  ← 主App,负责组装
│   (Host)     │
└──────┬───────┘
│
┌─────────────┼─────────────┐
│             │             │
┌───▼───┐   ┌────▼────┐   ┌────▼────┐
│首页业务│   │购物车业务 │   │ 我的业务 │  ← 业务组件
└───┬───┘   └────┬────┘   └────┬────┘
│            │             │
└────────────┼─────────────┘
│
┌────────────┼────────────┐
│            │            │
┌───▼───┐   ┌───▼───┐   ┌────▼────┐
│ 分享   │   │ 支付   │   │ 登录    │    ← 功能组件
└───┬───┘   └───┬───┘   └────┬────┘
│           │            │
└───────────┼────────────┘
│
┌───────────┼───────────┐
│           │           │
┌───▼───┐  ┌───▼───┐  ┌────▼────┐
│ 网络库 │  │ UI库  │  │ 工具库   │     ← 基础组件
└───────┘  └───────┘  └─────────┘
*/
// MARK: - 基础组件示例
/// 基础组件:无业务属性,纯技术能力封装
public class NetworkKit {

public static let shared = NetworkKit()
public func request<T: Decodable>(
  _ endpoint: Endpoint,
  responseType: T.Type
  ) async throws -> T {
  
  // 网络请求实现
  }
  }
  // MARK: - 功能组件示例
  /// 功能组件:可复用的业务功能
  public class ShareKit {
  
  public static func share(
  content: ShareContent,
  from viewController: UIViewController,
  completion: @escaping (Result<Void, Error>) -> Void
    ) {
    
    // 分享实现
    }
    }
    // MARK: - 业务组件示例
    /// 业务组件:具体业务模块
    public class HomeModule: ModuleProtocol {
    
    public static func initialize() {
    
    // 模块初始化
    }
    public static func createViewController() -> UIViewController {
    
    return HomeViewController()
    }
    }

组件依赖原则

依赖规则图示:
        ┌─────────────┐
        │   业务层    │  最上层
        └──────┬──────┘
               │ 依赖
               ▼
        ┌─────────────┐
        │   功能层    │  中间层
        └──────┬──────┘
               │ 依赖
               ▼
        ┌─────────────┐
        │   基础层    │  最底层
        └─────────────┘
规则:
✅ 上层可以依赖下层
✅ 同层之间通过协议/中间件通信
❌ 下层不可依赖上层
❌ 禁止循环依赖

模块拆分策略

拆分维度分析

/*
模块拆分考虑因素:
1. 业务边界
┌────────────────────────────────────────────┐
│  电商App业务域划分                           │
├────────────┬────────────┬─────────────────┤
│  商品域    │   交易域    │    用户域        │
│  ├─商品详情 │  ├─购物车   │   ├─登录注册     │
│  ├─商品搜索 │  ├─订单     │   ├─个人中心     │
│  └─商品分类 │  └─支付     │   └─消息通知     │
└────────────┴────────────┴─────────────────┘
2. 团队结构
┌────────────────────────────────────────────┐
│  按团队划分模块                              │
├────────────┬────────────┬─────────────────┤
│  A团队     │   B团队     │    C团队        │
│  负责首页   │  负责交易    │   负责用户      │
└────────────┴────────────┴─────────────────┘
3. 变更频率
┌────────────────────────────────────────────┐
│  高频变更  →  独立组件,快速迭代              │
│  低频变更  →  可合并,减少维护成本            │
└────────────────────────────────────────────┘
*/
// MARK: - 模块拆分示例
/// 业务模块定义
enum BusinessModule: String, CaseIterable {

case home = "Home"           // 首页模块
case product = "Product"     // 商品模块
case cart = "Cart"           // 购物车模块
case order = "Order"         // 订单模块
case user = "User"           // 用户模块
case message = "Message"     // 消息模块
/// 模块优先级(用于启动顺序)
var priority: Int {

switch self {

case .user: return 100     // 用户模块最先初始化
case .message: return 90
case .home: return 80
case .product: return 70
case .cart: return 60
case .order: return 50
}
}
}
/// 功能模块定义
enum FeatureModule: String {

case share = "Share"         // 分享
case payment = "Payment"     // 支付
case push = "Push"           // 推送
case analytics = "Analytics" // 数据统计
case imageLoader = "Image"   // 图片加载
}
/// 基础模块定义
enum CoreModule: String {

case network = "Network"     // 网络
case database = "Database"   // 数据库
case cache = "Cache"         // 缓存
case log = "Log"             // 日志
case router = "Router"       // 路由
}

Podfile 组织结构

# Podfile 组件化配置示例
platform :ios, '13.0'
use_frameworks!
inhibit_all_warnings!
# ========================
# 组件源配置
# ========================
source 'https://github.com/CocoaPods/Specs.git'           # 公共源
source 'https://your-company.com/ios-specs.git'           # 私有源
# ========================
# 抽象目标 - 公共依赖
# ========================
abstract_target 'CommonPods' do
# 基础层组件
pod 'CoreNetwork',    '~> 1.0'
pod 'CoreDatabase',   '~> 1.0'
pod 'CoreCache',      '~> 1.0'
pod 'CoreLogger',     '~> 1.0'
pod 'CoreRouter',     '~> 1.0'
pod 'CoreUIKit',      '~> 1.0'
# 功能层组件
pod 'FeatureShare',   '~> 1.0'
pod 'FeaturePayment', '~> 1.0'
pod 'FeaturePush',    '~> 1.0'
# 主工程
target 'MainApp' do
# 业务层组件
pod 'BizHome',      '~> 1.0'
pod 'BizProduct',   '~> 1.0'
pod 'BizCart',      '~> 1.0'
pod 'BizOrder',     '~> 1.0'
pod 'BizUser',      '~> 1.0'
pod 'BizMessage',   '~> 1.0'
target 'MainAppTests' do
inherit! :search_paths
pod 'Quick'
pod 'Nimble'
end
end
# 组件独立调试工程
target 'BizHomeDemo' do
pod 'BizHome', :path => '../BizHome'
end
target 'BizProductDemo' do
pod 'BizProduct', :path => '../BizProduct'
end
end
# ========================
# Post Install Hook
# ========================
post_install do |installer|
installer.pods_project.targets.each do |target|
target.build_configurations.each do |config|
config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '13.0'
# 开启模块稳定性
config.build_settings['BUILD_LIBRARY_FOR_DISTRIBUTION'] = 'YES'
end
end
end

组件 Podspec 规范

# BizHome.podspec - 业务组件规范
Pod::Spec.new do |s|
s.name             = 'BizHome'
s.version          = '1.0.0'
s.summary          = '首页业务组件'
s.description      = <<-DESC
首页业务组件,包含:
- 首页推荐流
- Banner轮播
- 分类入口
- 活动专区
DESC
s.homepage         = 'https://your-company.com/BizHome'
s.license          = {
 :type => 'MIT', :file => 'LICENSE' }
s.author           = {
 'iOS Team' => 'ios@company.com' }
s.source           = {
 :git => 'https://github.com/company/BizHome.git', :tag => s.version.to_s }
s.ios.deployment_target = '13.0'
s.swift_version = '5.0'
# 源码
s.source_files = 'BizHome/Classes/**/*'
# 资源文件
s.resources = 'BizHome/Assets/**/*'
s.resource_bundles = {

'BizHomeBundle' => ['BizHome/Assets/*.xcassets', 'BizHome/Assets/*.xib']
}
# 公开头文件(给其他组件使用的接口)
s.public_header_files = 'BizHome/Classes/Public/**/*.h'
# ========================
# 依赖声明(关键!)
# ========================
# 只依赖协议层,不依赖具体实现
s.dependency 'ServiceProtocols', '~> 1.0'
# 依赖基础组件
s.dependency 'CoreUIKit', '~> 1.0'
s.dependency 'CoreNetwork', '~> 1.0'
s.dependency 'CoreRouter', '~> 1.0'
# 依赖功能组件(通过协议)
# 注意:不直接依赖 BizProduct、BizCart 等业务组件!
# ========================
# 子模块划分
# ========================
s.subspec 'Core' do |core|
core.source_files = 'BizHome/Classes/Core/**/*'
end
s.subspec 'UI' do |ui|
ui.source_files = 'BizHome/Classes/UI/**/*'
ui.dependency 'BizHome/Core'
end
s.default_subspecs = 'Core', 'UI'
end

依赖反转原则

依赖反转核心思想

传统依赖 vs 依赖反转
【传统依赖】
┌─────────────┐          ┌─────────────┐
│   首页模块   │ ──────→ │   商品模块   │
│  (高层模块)  │   依赖   │  (低层模块)  │
└─────────────┘          └─────────────┘
问题:首页直接依赖商品模块,耦合严重
【依赖反转】
┌─────────────┐          ┌─────────────────┐
│   首页模块   │ ──────→ │  商品服务协议     │
│  (高层模块)  │   依赖   │  (抽象)         │
└─────────────┘          └────────┬────────┘
                                  │
                                  │ 实现
                                  │
                         ┌────────▼────────┐
                         │    商品模块      │
                         │   (具体实现)     │
                         └─────────────────┘
优势:
✅ 高层模块不依赖低层模块
✅ 两者都依赖抽象
✅ 抽象不依赖细节
✅ 细节依赖抽象

协议层设计

// MARK: - 服务协议层(独立Pod: ServiceProtocols)
// ═══════════════════════════════════════════════════════
// 商品服务协议
// ═══════════════════════════════════════════════════════
/// 商品信息模型(协议层定义,与具体模块无关)
public struct ProductInfo: Codable, Hashable {

public let id: String
public let name: String
public let price: Decimal
public let imageURL: URL?
public let description: String
public let stock: Int
public init(id: String, name: String, price: Decimal,
imageURL: URL?, description: String, stock: Int) {

self.id = id
self.name = name
self.price = price
self.imageURL = imageURL
self.description = description
self.stock = stock
}
}
/// 商品服务协议
public protocol ProductServiceProtocol {

/// 获取商品详情
func fetchProduct(by id: String) async throws -> ProductInfo
/// 获取商品列表
func fetchProducts(category: String, page: Int, pageSize: Int) async throws -> [ProductInfo]
/// 搜索商品
func searchProducts(keyword: String) async throws -> [ProductInfo]
/// 获取商品详情页
func productDetailViewController(productId: String) -> UIViewController
}
// ═══════════════════════════════════════════════════════
// 购物车服务协议
// ═══════════════════════════════════════════════════════
/// 购物车项模型
public struct CartItem: Codable, Identifiable {

public let id: String
public let productId: String
public let productName: String
public let price: Decimal
public var quantity: Int
public let imageURL: URL?
public init(id: String, productId: String, productName: String,
price: Decimal, quantity: Int, imageURL: URL?) {

self.id = id
self.productId = productId
self.productName = productName
self.price = price
self.quantity = quantity
self.imageURL = imageURL
}
}
/// 购物车服务协议
public protocol CartServiceProtocol {

/// 添加商品到购物车
func addToCart(productId: String, quantity: Int) async throws
/// 从购物车移除商品
func removeFromCart(itemId: String) async throws
/// 更新购物车商品数量
func updateQuantity(itemId: String, quantity: Int) async throws
/// 获取购物车列表
func fetchCartItems() async throws -> [CartItem]
/// 获取购物车商品数量(用于Tab角标)
func cartItemCount() -> Int
/// 购物车数量变化通知
var cartCountPublisher: AnyPublisher<Int, Never> {
   get }
  }
  // ═══════════════════════════════════════════════════════
  // 用户服务协议
  // ═══════════════════════════════════════════════════════
  /// 用户信息模型
  public struct UserInfo: Codable {
  
  public let userId: String
  public let nickname: String
  public let avatar: URL?
  public let phone: String?
  public let isVip: Bool
  public init(userId: String, nickname: String, avatar: URL?,
  phone: String?, isVip: Bool) {
  
  self.userId = userId
  self.nickname = nickname
  self.avatar = avatar
  self.phone = phone
  self.isVip = isVip
  }
  }
  /// 登录状态
  public enum LoginState {
  
  case notLogin
  case logging
  case logged(UserInfo)
  case expired
  }
  /// 用户服务协议
  public protocol UserServiceProtocol {
  
  /// 当前登录状态
  var currentState: LoginState {
   get }
  /// 登录状态变化发布者
  var statePublisher: AnyPublisher<LoginState, Never> {
     get }
    /// 获取当前用户信息
    func currentUser() -> UserInfo?
    /// 是否已登录
    func isLoggedIn() -> Bool
    /// 登录
    func login(phone: String, code: String) async throws -> UserInfo
    /// 登出
    func logout() async throws
    /// 展示登录页面
    func presentLoginIfNeeded(from viewController: UIViewController,
    completion: @escaping (Bool) -> Void)
    }
    // ═══════════════════════════════════════════════════════
    // 订单服务协议
    // ═══════════════════════════════════════════════════════
    /// 订单状态
    public enum OrderStatus: String, Codable {
    
    case pending = "pending"           // 待支付
    case paid = "paid"                 // 已支付
    case shipping = "shipping"         // 配送中
    case delivered = "delivered"       // 已送达
    case completed = "completed"       // 已完成
    case cancelled = "cancelled"       // 已取消
    }
    /// 订单信息
    public struct OrderInfo: Codable, Identifiable {
    
    public let id: String
    public let orderNo: String
    public let status: OrderStatus
    public let totalAmount: Decimal
    public let items: [OrderItem]
    public let createTime: Date
    public struct OrderItem: Codable {
    
    public let productId: String
    public let productName: String
    public let price: Decimal
    public let quantity: Int
    }
    }
    /// 订单服务协议
    public protocol OrderServiceProtocol {
    
    /// 创建订单
    func createOrder(from cartItems: [CartItem], addressId: String) async throws -> OrderInfo
    /// 获取订单列表
    func fetchOrders(status: OrderStatus?, page: Int) async throws -> [OrderInfo]
    /// 获取订单详情
    func fetchOrderDetail(orderId: String) async throws -> OrderInfo
    /// 取消订单
    func cancelOrder(orderId: String) async throws
    /// 订单详情页
    func orderDetailViewController(orderId: String) -> UIViewController
    }
    // ═══════════════════════════════════════════════════════
    // 路由服务协议
    // ═══════════════════════════════════════════════════════
    /// 路由路径定义
    public enum RoutePath {
    
    case home
    case productDetail(productId: String)
    case productList(category: String)
    case cart
    case order(orderId: String)
    case orderList(status: OrderStatus?)
    case userCenter
    case login
    case webView(url: URL, title: String?)
    case custom(path: String, params: [String: Any])
    public var pathString: String {
    
    switch self {
    
    case .home: return "/home"
    case .productDetail(let id): return "/product/\(id)"
    case .productList(let category): return "/products?category=\(category)"
    case .cart: return "/cart"
    case .order(let id): return "/order/\(id)"
    case .orderList: return "/orders"
    case .userCenter: return "/user"
    case .login: return "/login"
    case .webView(let url, _): return "/web?url=\(url.absoluteString)"
    case .custom(let path, _): return path
    }
    }
    }
    /// 路由服务协议
    public protocol RouterServiceProtocol {
    
    /// 注册路由处理器
    func register(path: String, handler: @escaping (URL, [String: Any]) -> UIViewController?)
    /// 导航到指定路径
    func navigate(to path: RoutePath, from viewController: UIViewController?, animated: Bool)
    /// 通过URL导航
    func open(url: URL, from viewController: UIViewController?)
    /// 返回
    func goBack(from viewController: UIViewController, animated: Bool)
    /// 返回到根视图
    func popToRoot(from viewController: UIViewController, animated: Bool)
    }

服务注册与发现

// MARK: - 服务容器(依赖注入容器)
/// 服务容器 - 单例模式
public final class ServiceContainer {

public static let shared = ServiceContainer()
private var services: [String: Any] = [:]
private var factories: [String: () -> Any] = [:]
private let lock = NSRecursiveLock()
private init() {
}
// ═══════════════════════════════════════════════════════
// 注册服务
// ═══════════════════════════════════════════════════════
/// 注册服务实例(单例模式)
public func register<T>(_ type: T.Type, instance: T) {
  
  lock.lock()
  defer {
   lock.unlock() }
  let key = String(describing: type)
  services[key] = instance
  print(" [ServiceContainer] Registered: \(key)")
  }
  /// 注册服务工厂(每次获取创建新实例)
  public func registerFactory<T>(_ type: T.Type, factory: @escaping () -> T) {
    
    lock.lock()
    defer {
     lock.unlock() }
    let key = String(describing: type)
    factories[key] = factory
    print(" [ServiceContainer] Registered Factory: \(key)")
    }
    /// 注册服务工厂(懒加载单例)
    public func registerLazy<T>(_ type: T.Type, factory: @escaping () -> T) {
      
      lock.lock()
      defer {
       lock.unlock() }
      let key = String(describing: type)
      factories[key] = {
       [weak self] in
      if let existing = self?.services[key] as? T {
      
      return existing
      }
      let instance = factory()
      self?.services[key] = instance
      return instance
      }
      print(" [ServiceContainer] Registered Lazy: \(key)")
      }
      // ═══════════════════════════════════════════════════════
      // 获取服务
      // ═══════════════════════════════════════════════════════
      /// 获取服务(可选)
      public func resolve<T>(_ type: T.Type) -> T? {
        
        lock.lock(
posted @ 2026-01-12 10:54  clnchanpin  阅读(2)  评论(0)    收藏  举报