Objective-C 依赖注入实践:降低类间耦合的 5 个关键步骤

依赖注入(DI)通过将依赖对象的创建与使用分离,显著降低类间耦合度。以下是 Objective-C 中的实践步骤:

1. 识别硬编码依赖
// 反例:直接在类内部实例化依赖
@implementation OrderService
- (void)processOrder {
    DatabaseManager *dbManager = [[DatabaseManager alloc] init]; // 硬编码耦合
    [dbManager saveOrder];
}
@end

关键操作

  • 审查 .m 文件中的 [[Class alloc] init] 调用
  • 定位需要解耦的核心依赖(如网络层、数据库层)
2. 抽象依赖协议
// 定义协议抽象依赖
@protocol PaymentProcessor <NSObject>
- (void)handlePayment:(double)amount;
@end

// 协议实现类
@implementation PayPalProcessor <PaymentProcessor>
- (void)handlePayment:(double)amount { /*...*/ }
@end

优势

  • 符合依赖倒置原则(DIP)
  • 支持多态实现替换
3. 构造函数注入
// 通过初始化器注入依赖
@interface OrderService : NSObject
- (instancetype)initWithPaymentProcessor:(id<PaymentProcessor>)processor;
@end

@implementation OrderService {
    id<PaymentProcessor> _paymentProcessor;
}

- (instancetype)initWithPaymentProcessor:(id<PaymentProcessor>)processor {
    if (self = [super init]) {
        _paymentProcessor = processor; // 注入依赖
    }
    return self;
}

- (void)checkout {
    [_paymentProcessor handlePayment:100.0]; // 使用抽象接口
}
@end

使用场景

  • 必需依赖项
  • 依赖关系在生命周期内不变
4. 属性注入
// 通过公开属性注入
@interface AnalyticsService : NSObject
@property (strong, nonatomic) id<EventTracker> tracker; // 可替换依赖
@end

// 使用时动态注入
AnalyticsService *analytics = [AnalyticsService new];
analytics.tracker = [[FirebaseTracker alloc] init]; // 运行时注入

适用场景

  • 可选依赖项
  • 需要运行时动态替换实现
5. 依赖容器集成
// 使用 Typhoon 框架示例
@interface ApplicationAssembly : TyphoonAssembly
- (OrderService *)orderService;
- (id<PaymentProcessor>)paymentProcessor;
@end

@implementation ApplicationAssembly
- (OrderService *)orderService {
    return [TyphoonDefinition withClass:[OrderService class] 
        configuration:^(TyphoonDefinition *definition) {
            [definition injectProperty:@selector(paymentProcessor) 
                                with:[self paymentProcessor]];
    }];
}

- (id<PaymentProcessor>)paymentProcessor {
    return [TyphoonDefinition withClass:[StripeProcessor class]];
}
@end

容器优势

  • 集中管理依赖关系
  • 自动解决依赖链
  • 支持单例/原型作用域控制

效果验证

// 单元测试示例(使用 OCMock)
- (void)testOrderProcessing {
    // 1. 创建协议模拟对象
    id mockProcessor = OCMProtocolMock(@protocol(PaymentProcessor));
    
    // 2. 注入模拟依赖
    OrderService *service = [[OrderService alloc] initWithPaymentProcessor:mockProcessor];
    
    // 3. 验证交互行为
    OCMExpect([mockProcessor handlePayment:100.0]);
    [service checkout];
    OCMVerifyAll(mockProcessor);
}

耦合度变化: $$ \text{耦合系数} = \frac{\text{直接依赖}}{\text{总类数}} \rightarrow 0.2 \text{(DI后)} \quad vs \quad 0.8 \text{(DI前)} $$

最佳实践

  1. 组合优于继承:通过 DI 实现对象组合
  2. 接口隔离:每个协议专注单一能力
  3. 循环依赖检测:使用 __weak 打破强引用环
  4. 分层注入:基础设施层 → 领域层 → 表示层

通过这 5 步,可使模块间依赖变为可配置的弱连接,显著提升代码可测试性和架构灵活性。典型应用场景:服务层替换、测试替身注入、多环境配置切换。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐