Skip to content

Latest commit

 

History

History
222 lines (176 loc) · 5.72 KB

DependencyInjection.md

File metadata and controls

222 lines (176 loc) · 5.72 KB

依赖注入和依赖查找

依赖注入和依赖查找是实现控制反转的方式。

控制反转是将对象依赖的获取从主动变为被动,从对象内部直接引用并获取依赖,变为由外部向对象提供对象所要求的依赖,从而让对象和其依赖解耦。

依赖注入

依赖注入是指外部向对象传入依赖。

一个类 A 在接口中体现出内部需要用到的一些依赖(例如内部需要用到类B的实例),从而让使用者从外部注入这些依赖,而不是在类内部直接引用依赖并创建类 B。依赖可以用 protocol 的方式声明,这样就可以使类 A 和所使用的依赖类 B 进行解耦。

初始化注入

初始化注入是指类在初始化方法里添加的一些必需依赖。这些依赖是创建对象的时候必须要用到的。

protocol Name {
    var firstName: String { get }
    var lastName: String { get }
}

class Person {
    let name: Name
    init(name: Name) {
        self.name = name
    }
}
Objective-C示例
@protocol Name
- (NSString *)firstName;
- (NSString *)lastName;
@end

@interface Person: NSObject
@property (nonatomic, strong) id<Name> name;
- (instancetype)initWithName:(id<Name>)name;
@end

在 router 里,可以用 module config protocol 实现初始化依赖:

protocol PersonConfig {
    func constructWithName(_ name: Name) -> Void
}
class PersonConfiguration: ZIKPerformRouteConfiguration, PersonConfig {
    var name: Name?
    func constructWithName(name: Name) {
        self.name = name
    }
}
class PersonRouter: ZIKServiceRouter<Person, PersonConfiguration> {
    ...    
    override func destination(with configuration: PersonConfiguration) -> Person? {
        guard let name = configuration.name else {
            return nil
        }
        return Person(name: name)
    }
}

你可以约定调用者必须调用 config protocol 中以construct作为前缀的方法。

let name: Name = ...
let person = Router.makeDestination(to: RoutableServiceModule<PersonConfig>(), preparation: { moduleConfig in
            moduleConfig.constructWithName(name)
        })
Objective-C示例
@protocol PersonConfig: ZIKServiceModuleRoutable
- (void)constructWithName:(id<Name>)name;
@end

@interface PersonConfiguration: ZIKPerformConfiguration <PersonConfig>
@property (nonatomic, strong) id<Name> name;
- (void)constructWithName:(id<Name>)name;
@end
@implementation PersonConfiguration
- (void)constructWithName:(id<Name>)name {
    self.name = name;
}
@end

@interface PersonRouter: ZIKServiceRouter<Person *, PersonConfiguration *>
@end
@implementation PersonRouter

- (nullable Person *)destinationWithConfiguration:(PersonConfiguration *)configuration {
    id<Name> name = configuration.name;
    if (name == nil) {
        return nil;
    }
    return [[Person alloc] initWithName:name];
}

@end
id<Name> name = ...
Person *person = [ZIKRouterToServiceModule(PersonConfig) 
         makeDestinationWithConfiguring:^(ZIKPerformRouteConfiguration<PersonConfig> * _Nonnull config) {
            [config constructWithName:name];
        }];

属性注入和方法注入

当依赖是可选的,并不是创建对象所必需的,可以用属性注入和方法注入。

属性注入是指外部设置对象的属性。

方法注入是指外部调用对象的方法,从而传入依赖。

protocol PersonType {
    var wife: Person? { get set }
    func addChild(_ child: Person) -> Void
}
protocol Child {
    var parent: Person { get }
}

class Person: PersonType {
    var wife: Person? = nil
    var childs: Set<Child> = []
    func addChild(_ child: Child) {
        childs.insert(child)
    }
}
Objective-C示例
@protocol PersonType: ZIKServiceRoutable
@property (nonatomic, strong, nullable) Person *wife;
- (void)addChild:(Person *)child;
@end
@protocol Child
@property (nonatomic, strong) Person *parent;
@end

@interface Person: NSObject <PersonType>
@property (nonatomic, strong, nullable) Person *wife;
@property (nonatomic, strong) NSSet<id<Child>> childs;
@end

在 router 里,可以注入一些默认的依赖:

class PersonRouter: ZIKServiceRouter<Person, ZIKPerformRouteConfiguration> {
    ...    
    override func destination(with configuration: ZIKPerformRouteConfiguration) -> Person? {
        let person = Person()
        //可以直接在router里设置默认值
        //person.wife = ...
        return person
    }
}

调用者也可以用PersonType动态地注入依赖。

let wife: Person = ...
let child: Child = ...
let person = Router.makeDestination(to: RoutableService<PersonType>(), preparation: { destination in
            destination.wife = wife
            destination.addChild(child)
        })
Objective-C示例
@interface PersonRouter: ZIKServiceRouter<Person *, ZIKPerformRouteConfiguration *>
@end
@implementation PersonRouter

- (nullable Person *)destinationWithConfiguration:(ZIKPerformRouteConfiguration *)configuration {
    Person *person = [Person new];
    ///[person addChild:...];
    return person;
}

@end
Person *wife = ...
Child *child = ...
Person *person = [ZIKRouterToService(PersonType) 
         makeDestinationWithPreparation:^(id<PersonType> destination) {
            destination.wife = wife;
            [destination addChild:child];
        }];

依赖查找

依赖查找是指在内部通过某种方式查找依赖。当使用 Router 获取模块的时候,就是在动态地查找依赖。


下一节:循环依赖问题