Java 中的中介模式(Mediator Pattern)

  • 2019 年 12 月 5 日
  • 笔记

1. 概述

在本文中,我们将介绍一种 GoF 行为模式——中介模式。我们将描述它的目的并说明何时应该使用它。

和往常一样,我们还提供简单的示例代码。

2. 中介模式

在面向对象编程中,我们应该总是尝试组件是松耦合和可复用的方式设计系统。这种方法使我们的代码更易于维护和测试。

然而,在现实生活中,我们经常需要处理一组复杂的依赖对象。这时中介模式会派上用场。

中给模式的目的是降低紧密耦合对象之间直接和其他对象通信的复杂性和依赖性。这是通过创建一个中介对象来实现的,该对象负责依赖对象之间的交互。因此,所有的通信都通过中介。

这促进了松耦合,因为一组组件一起工作不再需要直接交互。相反,他们只引用独立的中介对象。这样,在系统的其他部分中复用这些对象也更容易。

3. 中介模式的 UML 图

现在让我们直观的看看这个模式:

在上面的 UML 图中,我们可以识别一下参与者:

  • Mediator 定义了 Colleague 对象用于通信的接口
  • Colleague 定义了包含 Mediator 的单个引用的抽象类
  • ConcreteMediator 封装了 Colleague 对象之间的交互逻辑
  • ConcreteColleague1 和 ConcreteColleague2 只通过 Mediator 通信

我们可以看到,Colleague 对象不直接相互引用。相反的,所有通信都通过 Mediator 执行。

因此,ConcreteColleague1 和 ConcreteColleague2 可以更容易的复用。

另外,假如我们需要改变 Colleague 一起工作的方式,我们只需要修改 ConcreteMediator 的逻辑。或者我们可以创建新的 Mediator 的实现。

4. Java 实现

现在我们对这个理论有了清晰得认识,那么让我们看一个例子,在实践中更好得理解这个概念。

4.1. 示例场景

想象一下,我们正在构建一个简单的冷却系统,由风扇、电源和按钮组成。按下按钮将打开或关闭风扇。在我们打开风扇之前,我们需要打开电源。同样,我们必须在风扇关闭之后立即关闭电源。

现在让我们看一下示例实现:

    public class Button {            private Fan fan;              // constructor, getters and setters              public void press(){                if(fan.isOn()){                    fan.turnOff();                } else {                    fan.turnOn();                }            }        }        public class Fan {            private Button button;            private PowerSupplier powerSupplier;            private boolean isOn = false;              // constructor, getters and setters              public void turnOn() {                powerSupplier.turnOn();                isOn = true;            }              public void turnOff() {                isOn = false;                powerSupplier.turnOff();            }        }        public class PowerSupplier {            public void turnOn() {                // implementation            }              public void turnOff() {                // implementation            }        }

接下来,让我们测试一下这个功能:

    @Test        public void givenTurnedOffFan_whenPressingButtonTwice_fanShouldTurnOnAndOff() {            assertFalse(fan.isOn());              button.press();            assertTrue(fan.isOn());              button.press();            assertFalse(fan.isOn());        }

一切看起来运行正常。但请注意Button、Fan 和 PowerSupplier 类是紧耦合的。Button 直接操作 Fan,Fan 与 Button 和 PowerSupplier 都进行交互。

在其他模块中复用 Button 类会很困难。此外,如果我们需要在系统中添加第二个电源,那么我们必须修改 Fan 类的逻辑。

4.2. 添加中介模式

现在,让我们实现中介模式以减少我们类之间的依赖,是代码更具可复用性。

首先,让我们介绍 Mediator 类:

    public class Mediator {            private Button button;            private Fan fan;            private PowerSupplier powerSupplier;              // constructor, getters and setters              public void press() {                if (fan.isOn()) {                    fan.turnOff();                } else {                    fan.turnOn();                }            }              public void start() {                powerSupplier.turnOn();            }              public void stop() {                powerSupplier.turnOff();            }        }

接下来,让我们修改剩下的类:

    public class Button {            private Mediator mediator;              // constructor, getters and setters              public void press() {                mediator.press();            }        }        public class Fan {            private Mediator mediator;            private boolean isOn = false;              // constructor, getters and setters              public void turnOn() {                mediator.start();                isOn = true;            }              public void turnOff() {                isOn = false;                mediator.stop();            }        }

让我们再一次测试这个功能:

    @Test        public void givenTurnedOffFan_whenPressingButtonTwice_fanShouldTurnOnAndOff() {            assertFalse(fan.isOn());              button.press();            assertTrue(fan.isOn());              button.press();            assertFalse(fan.isOn());        }

我们的冷却系统按预期工作。

现在我们已经实现了中介模式,Button、Fan 或 PowerSupplier 类都没有直接通信。他们只有一个对 Mediator 的引用。

如果我们将来需要添加第二个电源,我们需要做的只是更新 Mediator 的逻辑;Button 和 Fan 类保持不变。

这个示例展示了我们可以轻松的分离依赖的对象并使我们的系统更易于维护。

5. 何时使用中介模式

如果我们必须处理一组紧耦合且难以维护的对象时,中介模式是一个不错的选择。这样我们可以减少对象间的依赖并降低整体复杂性。

此外,通过使用中介对象,我们将通信逻辑提取到单个组件,这样,我们遵循了单一职责原则。此外,我们可以引入新的中介而不需要更改系统的其余部分。因此,我们遵循开闭原则(译者注:对扩展开放,对修改封闭)。

然而,有时由于系统的错误设计,我们可能会由太多紧耦合对象。如果是这种情况,我们不应该应用中介模式。相反的,我们应该后退一步,重新思考对类建模的方式。

和所有其他模式一样,我们需要在盲目实现中介模式前考虑我们的特殊用例。

6. 总结

在本文中,我们了解了中介模式。我们说明了这个模式解决了什么问题以及我们什么时候应该实际考虑使用它。我们还实现了这个设计模式的一个简单示例。