iOS设计模式之中介者模式

239 阅读4分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第9天,点击查看活动详情

  • 本文主要介绍iOS设计模式中的中介者模式,中介者模式主要是为了解耦,可以避免各个对象相互引用导致耦合性太强

1. 什么是中介者模式

在机场我们可以发现飞机都是有条不紊的进行起飞和降落,这都是通过集中的空中交通管制,要是没有管制那么飞机起飞和降落就会变得危险而复杂。我们在开车的过程中,十字路口的红绿灯其实也是扮演着交通管理者,我们可以发现当红绿灯坏的时候,路口交通就变得异常拥堵,过往车辆都要小心通过。
在面向对象软件中,我们在设计中见过很多这样的场景。典型的例子是应用程序中的UI元素。比如有个对话框带有静态文本,列表框,文本框,以及多个输入框。当列表框中的一项被选中时,静态文本会被跟新列表框选定的值。当更多的UI元素参与到这一错综复杂关系时,就会变得难以控制。这个时候就需要一个交通管理员来管理所有的UI交流
面向对象的设计鼓励把行为分散到不同的对象中。这种分散可能导致对象之间的相互关联。在最糟糕的情况下,所有对象都彼此了解并相互操作。
虽然把行为分散到不同对象增强了可复用性,但是增加的相互关联又减少了获得的益处。增加的关联使得对象很难或不能在不依赖其他对象的情况下工作。中介者模式用于定义一个集中的场所,对象间的交互可以在一个中介者对象中处理。其他对象不必彼此交互,因此减少了它们之间的依存关系。

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

2. 什么时候使用中介者模式

以下几种常见的情形下,可以考虑使用这一模式。

  • 对象间的交互虽定义明确然而非常复杂,导致一组对彼此相互依赖而且难以理解。
  • 因为对象引用了许多其他对象并与其通讯,导致对象难以复用
  • 想要定制一个分布在多个类中的逻辑或行为,又不想生成太多子类

3. 代码展示

可以发现我么通过Mediator中介者持用对象,对象持有中介者,从而达到间接的交互

import XCTest

/// The Mediator interface declares a method used by components to notify the
/// mediator about various events. The Mediator may react to these events and
/// pass the execution to other components.
protocol Mediator: AnyObject {

    func notify(sender: BaseComponent, event: String)
}

/// Concrete Mediators implement cooperative behavior by coordinating several
/// components.
class ConcreteMediator: Mediator {

    private var component1: Component1
    private var component2: Component2

    init(_ component1: Component1, _ component2: Component2) {
        self.component1 = component1
        self.component2 = component2

        component1.update(mediator: self)
        component2.update(mediator: self)
    }

    func notify(sender: BaseComponent, event: String) {
        if event == "A" {
            print("Mediator reacts on A and triggers following operations:")
            self.component2.doC()
        }
        else if (event == "D") {
            print("Mediator reacts on D and triggers following operations:")
            self.component1.doB()
            self.component2.doC()
        }
    }
}

/// The Base Component provides the basic functionality of storing a mediator's
/// instance inside component objects.
class BaseComponent {

    fileprivate weak var mediator: Mediator?

    init(mediator: Mediator? = nil) {
        self.mediator = mediator
    }

    func update(mediator: Mediator) {
        self.mediator = mediator
    }
}

/// Concrete Components implement various functionality. They don't depend on
/// other components. They also don't depend on any concrete mediator classes.
class Component1: BaseComponent {

    func doA() {
        print("Component 1 does A.")
        mediator?.notify(sender: self, event: "A")
    }

    func doB() {
        print("Component 1 does B.\n")
        mediator?.notify(sender: self, event: "B")
    }
}

class Component2: BaseComponent {

    func doC() {
        print("Component 2 does C.")
        mediator?.notify(sender: self, event: "C")
    }

    func doD() {
        print("Component 2 does D.")
        mediator?.notify(sender: self, event: "D")
    }
}

/// Let's see how it all works together.
class MediatorConceptual: XCTestCase {

    func testMediatorConceptual() {

        let component1 = Component1()
        let component2 = Component2()

        let mediator = ConcreteMediator(component1, component2)
        print("Client triggers operation A.")
        component1.doA()

        print("\nClient triggers operation D.")
        component2.doD()

        print(mediator)
    }
}

执行结果

Client triggers operation A.
Component 1 does A.
Mediator reacts on A and triggers following operations:
Component 2 does C.

Client triggers operation D.
Component 2 does D.
Mediator reacts on D and triggers following operations:
Component 1 does B.

Component 2 does C.

对于一些UI跳转的情况我们也可以使用中介者模式,并让中介者成为单例

4. 总结

中介者模式降低了对象直接的相互耦合性,和交互性。但是中介者模式以中介者内部的复杂性代替交互的复杂性。因为中介者封装与合并了各个对象的各种协作逻辑,自身可能变得比它们任何一个都复杂。这会让中介者成为无所不知的庞然大物,并且难以维护。这个过程我们可以使用另外一种模式把它分解,比如使用策略模式或者责任链模式。要创造性地混用和组合各种设计模式解决同一个问题