Swift中介者模式

201 阅读3分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第1天,点击查看活动详情

一、中介者模式

介绍

中介者模式(Mediator Pattern)是用来降低多个对象和类之间的通信复杂性。这种模式提供了一个中介类,该类通常处理不同类之间的通信,并支持松耦合,使代码易于维护。中介者模式属于行为型模式。

简单来说:用一个中介对象来封装一系列的对象的交互。中介者使各对象不需要显示地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。

1.结构

设想:我们要在VC中使用NSTimer并每秒打印"timerFire",代码如下:

var nyTimer: Timer?
    override func viewDidLoad() {
        super.viewDidLoad()
        nyTimer = Timer.init(timeInterval: 1, target: self, selector: #selector(timerFire), userInfo: nil, repeats: true)
        RunLoop.current.add(nyTimer!, forMode: .common)
    }
    
    @objc func timerFire() {
        print("timer fire")
    }
    
    deinit {
        print("\(self) 走了")
        nyTimer?.invalidate()
        nyTimer = nil
    }
    

image.png 可是以上代码会产生循环引用。如何修改才能解决呢?

类结构

  • 具体中介者(NYProxy)角色:实现中介者对,VC的NSObjectProtocol实现,Selector 外部事件,持有NSTimer。

中介者模式的核心在于中介者类的引入,在中介者模式中,中介者类承担了两方面的职责:  ( 所有对象之间的交互都 在 NYProxy 类中进行)

(1) 中转作用(结构性):通过中介者提供的中转作用,NSTimer对象就不再需要显式引用self,当需要和self进行通信时,可通过中介者来实现间接调用。该中转作用属于中介者在结构上的支持。

(2) 协调作用(行为性):中介者可以更进一步的对NSTimer和self进行封装,NSTimer可以一致的和中介者进行交互,而不需要指明中介者需要具体怎么做,中介者根据封装在自身内部的协调逻辑,对NSTimer的任务进一步处理,将NSTimer和slef之间的关系进一步分离和封装。该协调作用属于中介者在行为上的支持。

设计图

image.png

image.png

中介者(NYProxy),封装了NSTimer和self之间的关系。并且切断了NSTimer->target的直接指向VC-self,解决了循环引用问题。

2.案例实现

NYProxy核心代码:

class NYProxy: NSObject {

    weak var target: NSObjectProtocol?
    var sel: Selector?
    var nyTimer: Timer? = nil

    override init(){
        super.init()
    }    
    
    
    func ny_scheduledTimer(timeInterval:TimeInterval,target:Any,selector:Selector,userInfo:Any?,repeats:Bool){
        self.nyTimer = Timer.init(timeInterval: timeInterval, target: self, selector: selector, userInfo: userInfo, repeats: repeats)
        RunLoop.current.add(self.nyTimer!, forMode: .common)

        self.target = target as? NSObjectProtocol
        self.sel = selector
        guard self.target?.responds(to: sel) == true else{
            return
        }

        let method = class_getInstanceMethod(self.classForCoder, #selector(TimerFire))
        class_replaceMethod(self.classForCoder, self.sel!, method_getImplementation(method!), method_getTypeEncoding(method!))//交换函数

    }

    
    @objc fileprivate func TimerFire() {
        if self.target != nil {
            self.target?.perform(self.sel)
        } else {
            self.nyTimer?.invalidate()
            self.nyTimer = nil
        }
    }
    
    deinit {
        print("\(self) 走了")
    }

    override func forwardingTarget(for aSelector: Selector!) -> Any? {
        if self.target?.responds(to: self.sel) == true {
            return self.target
        } else {
            //容错处理
            print("找不到sel")
            return super.forwardingTarget(for: aSelector)
        }
    }
}

运行结果:

image.png

总结:

用一个中介对象来封装一系列的对象的交互。中介者使各对象不需要显示地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。降低多个对象和类之间的通信复杂性。在项目设计解藕中常常用到。