MST

星途 面试题库

面试题:Objective-C模块化设计中如何有效利用依赖注入处理复杂依赖关系

假设有一个大型Objective-C项目,模块A依赖模块B、模块C和模块D,而模块B又依赖模块E和模块F,模块D依赖模块G。请详细描述如何运用依赖注入来管理这些复杂的依赖关系,以提高代码的可维护性和可测试性,并给出关键代码示例。
11.7万 热度难度
编程语言Objective-C

知识考点

AI 面试

面试题答案

一键面试

依赖注入概念

依赖注入(Dependency Injection,简称DI)是一种设计模式,通过将对象所依赖的外部对象传递给该对象,而不是让对象自己创建或查找依赖对象,从而实现解耦,提高代码的可维护性和可测试性。

管理依赖关系步骤

  1. 定义协议:为每个模块定义协议,模块通过协议进行交互,而不是直接依赖具体实现类。
  2. 传递依赖:在需要使用依赖的模块中,通过构造函数、属性或方法参数的方式接收依赖对象。

关键代码示例

  1. 定义协议
// 模块B协议
@protocol ModuleBProtocol <NSObject>
// 模块B相关方法声明
@end

// 模块C协议
@protocol ModuleCProtocol <NSObject>
// 模块C相关方法声明
@end

// 模块D协议
@protocol ModuleDProtocol <NSObject>
// 模块D相关方法声明
@end

// 模块E协议
@protocol ModuleEProtocol <NSObject>
// 模块E相关方法声明
@end

// 模块F协议
@protocol ModuleFProtocol <NSObject>
// 模块F相关方法声明
@end

// 模块G协议
@protocol ModuleGProtocol <NSObject>
// 模块G相关方法声明
@end
  1. 模块实现
// 模块B实现
@interface ModuleB : NSObject <ModuleBProtocol>
@property (nonatomic, strong) id<ModuleEProtocol> moduleE;
@property (nonatomic, strong) id<ModuleFProtocol> moduleF;
- (instancetype)initWithModuleE:(id<ModuleEProtocol>)moduleE moduleF:(id<ModuleFProtocol>)moduleF;
@end

@implementation ModuleB
- (instancetype)initWithModuleE:(id<ModuleEProtocol>)moduleE moduleF:(id<ModuleFProtocol>)moduleF {
    self = [super init];
    if (self) {
        _moduleE = moduleE;
        _moduleF = moduleF;
    }
    return self;
}
@end

// 模块D实现
@interface ModuleD : NSObject <ModuleDProtocol>
@property (nonatomic, strong) id<ModuleGProtocol> moduleG;
- (instancetype)initWithModuleG:(id<ModuleGProtocol>)moduleG;
@end

@implementation ModuleD
- (instancetype)initWithModuleG:(id<ModuleGProtocol>)moduleG {
    self = [super init];
    if (self) {
        _moduleG = moduleG;
    }
    return self;
}
@end
  1. 模块A使用依赖注入
@interface ModuleA : NSObject
@property (nonatomic, strong) id<ModuleBProtocol> moduleB;
@property (nonatomic, strong) id<ModuleCProtocol> moduleC;
@property (nonatomic, strong) id<ModuleDProtocol> moduleD;
- (instancetype)initWithModuleB:(id<ModuleBProtocol>)moduleB moduleC:(id<ModuleCProtocol>)moduleC moduleD:(id<ModuleDProtocol>)moduleD;
@end

@implementation ModuleA
- (instancetype)initWithModuleB:(id<ModuleBProtocol>)moduleB moduleC:(id<ModuleCProtocol>)moduleC moduleD:(id<ModuleDProtocol>)moduleD {
    self = [super init];
    if (self) {
        _moduleB = moduleB;
        _moduleC = moduleC;
        _moduleD = moduleD;
    }
    return self;
}
@end
  1. 使用示例
// 创建模块E、F、G实例
id<ModuleEProtocol> moduleE = [[ModuleE alloc] init];
id<ModuleFProtocol> moduleF = [[ModuleF alloc] init];
id<ModuleGProtocol> moduleG = [[ModuleG alloc] init];

// 创建模块B、D实例并注入依赖
id<ModuleBProtocol> moduleB = [[ModuleB alloc] initWithModuleE:moduleE moduleF:moduleF];
id<ModuleDProtocol> moduleD = [[ModuleD alloc] initWithModuleG:moduleG];

// 创建模块C实例
id<ModuleCProtocol> moduleC = [[ModuleC alloc] init];

// 创建模块A实例并注入依赖
ModuleA *moduleA = [[ModuleA alloc] initWithModuleB:moduleB moduleC:moduleC moduleD:moduleD];

通过上述方式,利用依赖注入管理了复杂的依赖关系,使得每个模块的职责清晰,可维护性和可测试性得到提升。在测试时,可以很方便地替换具体依赖对象为模拟对象,从而对单个模块进行独立测试。