依赖注入-iOS

依赖

依赖:在ClassA(调用者)中初始化ClassB(被调用者)的实例,那么ClassA对ClassB有一个依赖。

class ClassA {
    
    var classB: ClassB
    
    init() {
        self.classB = ClassB()
    }
}

依赖注入

依赖注入:ClassA(调用者)非自己主动创建ClassB(被调用者)的实例,而是通过外部(第三方)完成ClassB的创建,然后注入到ClassA中,就称为依赖注入

调用者不再直接创建依赖,而是通过注入依赖,持有被调用者。

class ClassA {
    
    var classB: ClassB
    
    init(classB: ClassB) {
        self.classB = classB
    }

}

控制反转

创建ClassB的工作不再由调用者ClassA来完成,而是借助第三方实现具体依赖关系的创建,ClassA创建ClassB由主动行为变成了被动行为,ClassA创建ClassB的控制权也因此由主动变被动,因此称为 控制反转。(Class也可以改为模块、组件等)

控制反转.png

注入方式

注入方式:构造器注入、设值(setter)注入、接口注入。

构造器注入:
init(classB: ClassB) {
        self.classB = classB
 }
setter注入:
Swift: var classB: ClassB?
OC: @property (nonatomic, strong) ClassB *ClassB;

接口注入:
func injectClassB(classB: ClassB) {
        self.classB = classB;
 }

依赖注入解决的问题:

1.利于单元测试或者Mock测试。

2.解耦,将依赖之间进行解耦, 分离了调用方和被调用方。

3.无需在修改ClassB创建方式时,需要修改ClassA的代码,同时ClassA不用关心ClassB创建细节,只用关心ClassB提供的服务。

4.依赖变成抽象接口依赖提高扩展性。ClassC提供了ClassB类似服务,可以方便切换成ClassC。

5.通过NSClassFromStirng转换成同名的类,即反射机制实现运行时动态控制依赖对象的引入。

依赖反转(依赖倒置原则)

上层模块不应该依赖底层模块,上层和底层都应该依赖于抽象,上层模块定义并依赖抽象接口,底层模块实现该接口。

依赖未反转
/** 底层B*/
public class ModuleB {
    
    public func setup() {
    
    }
}

let moduleManager = ModuleManager()
let moduleB = ModuleB()
moduleManager.setModuleB(module: moduleB)
// 如果新增了ModuleC 还需要在moduleManager中新增方法setModuleC,如下:    
let moduleC = ModuleC()
moduleManager.setModuleC(module: moduleC)
依赖反转

/** 定义模块接口*/
protocol ModuleProtocol {
    func setup()
}

/** 底层B*/
public class ModuleB: ModuleProtocol {
    
    public func setup() {
    
    }
}
/** 底层C*/
public class ModuleC: ModuleProtocol {
    
    public  func setup() {
        
    }
}

/** 高层*/
class ModuleManager {
    // 注册单个module
    func setModule(moudle: ModuleProtocol) {
        moudle.setup()
    }

    // 注册多个module
    func setModules(modules: [ModuleProtocol]) {
        for module in modules {
            module.setup()
        }
    }
}

var moduleManager = ModuleManager()
let moduleB = ModuleB()
moduleManager.setModule(module: moduleB)
新增底层模块ModuleC时,高层模块A不需要写兼容代码。
let moduleC = ModuleC()
moduleManager.setModule(module: moduleC)

依赖倒置指导接口隔离原则,最终目标是为了实现开闭原则,高层模块不用修改,对底层扩展开放,我们很容易新增、替换、删除底层模块,利于组件化。

依赖注入+依赖倒置.png

依赖注入的框架objection

参考资料:
https://www.jianshu.com/p/dabca5ab1a80
https://mp.weixin.qq.com/s/Zp-OqCVVr9CbDv1Y1zWN-w
https://github.com/android-cn/blog/tree/master/java/dependency-injection
https://baike.baidu.com/item/%E4%BE%9D%E8%B5%96%E6%B3%A8%E5%85%A5/5177233?fr=aladdin

你可能感兴趣的:(依赖注入-iOS)