Swinject:如何将委托模式与接口隔离(类与接口)一起使用?

Posted

技术标签:

【中文标题】Swinject:如何将委托模式与接口隔离(类与接口)一起使用?【英文标题】:Swinject: How to use delegate pattern with interface segregation (class vs interface)? 【发布时间】:2019-09-11 18:02:18 【问题描述】:

我正在努力解决注入依赖问题。现在问题来了,在委托模式的情况下如何使用接口隔离原则?我正在使用 Swinject 框架进行依赖注入。我该如何解决这个问题?

class Client 
    private var interface: ParentInterface

    ...

    func execute() 
        interface = globalContainer.resolve(ParentInterface.self)
        interface?.parentMethod()
    

protocol ParentInterface 
    func parentMethod()


class Parent: ParentInterface, ParentDelegate 

    // Dependency
    private var child: Child? // ???? I WANT TO USE AN PROTOCOL HERE, NOT THE CLASS

    init(childReference: Child) 
        self.child = childReference
        self.child?.delegate = self // ???? But if I use the protocol I cant access the delegate property
    

    public func parentMethod() 
        let result = calcSomething()

        // Access child class interface method
        child?.childMethod(result)
    
    ...

子类,目前没有什么异常。

protocol ParentDelegate: class 
    func delagteMethod(value: Double)


protocol ChildInterface 
    func childMethod(_ result: Double)


class Child: ChildInterface 

    weak var delegate: ParentDelegate?

    ...

    private func delagteMethod() 
      delegate?.delagteMethod(value: someValue)
    


但是要正确注入依赖项,我需要一个协议而不是直接的类引用,对吧?像这样:


// ???? Would like to
container.register(ParentInterface.self)  r in
    Parent(childInterface: r.resolve(ChildInterface.self)!)
 

// ???? Only way I get it working without interface
container.register(ParentDelegate.self)  r in
    Parent(childClass: Child())


container.register(ChildInterface.self)  _ in Child() 
    .initCompleted  r, c in
        let child = c as! Child
        child.delegate = r.resolve(ParentDelegate.self) 



简而言之,我在绕圈子。如果我为子类使用接口,我无法访问委托属性,如果我使用类引用,我无法合理模拟/存根接口方法。

我错过了什么?提前非常感谢!

【问题讨论】:

【参考方案1】:

我建议从Parent 构造函数中删除self.child?.delegate = self,原因有两个:

    不应该由 DI 框架负责连接所有依赖项吗? 特别是在 Swinject 中,这可能会导致不正确的依赖关系,请参阅 the remark in docs

我倾向于使用的模式或多或少是您想出的:

class Parent: ParentInterface, ParentDelegate  
    init(child: ChilInterface)  self.child = child 


class Child: ChildInterface 
    weak var parent: ParentDelegate?


container.register(ParentInterface.self)  Parent(child: $0.resolve(ChildInterface.self)!) 
    .implements(ParentDelegate.self)

container.register(ChildInterface.self)  _ in Child() 
    .initCompleted  ($1 as! Child).delegate = $0.resolve(ParentDelegate.self) 

此外,如果您想摆脱强制转换,您可以执行以下操作:

container.register(Child.self)  _ in Child() 
   .implements(ChildInterface.self)
   .initCompleted  $1.delegate = $0.resolve(ParentDelegate.self) 

【讨论】:

以上是关于Swinject:如何将委托模式与接口隔离(类与接口)一起使用?的主要内容,如果未能解决你的问题,请参考以下文章

代理模式与AOP

Java之动态代理简介

AOP实现原理

java动态代理实现与原理详细分析

java动态代理实现与原理详细分析

java动态代理实现与原理详细分析