详解Java中介模式
本文我们探讨GoF设计模式中的中介模式,详细说明其目的以及什么场景下使用。当然我会结合示例进行实战说明。
中介模式
面向对象编程中,我们始终应该让设计的系统组件保持松耦合并可重用。这会让我们代码更容易维护和测试。
实际应用中,我们经常需要处理复杂的对象之间依赖,这时中介模式就派上用场了。
中介模式的目的就是为了减少复杂性和依赖性,避免精密耦合对象之间直接通信。通过创建中介对象负责依赖对象之间的交互,因此,所有交互都通过中介对象实现。
这提升松耦合的可能,因为一组协同对象之间不再直接交互。相反它们依赖单个中介对象,这样增强了这些对象的课重用性。
中介模式的UML图
让我们先看下面uml图示:
在上面的uml途中,我们能识别下面一些参与者:
- 定义Mediator接口用于 Colleague 对象直接交互
- 定义抽象类Colleague,包括单个 Mediator引用
- ConcreteMediator类封装Colleague 对象直接交互逻辑
- ConcreteColleague1 和 ConcreteColleague2 仅通过 Mediator 进行交互
我们看到Colleague对象直接不相互直接引用,而是通过Mediator进行交互。因此,ConcreteColleague1 和 ConcreteColleague2可重用性增强。另外,当我们需要改变Colleague 对象直接的交互方式时,仅需修改ConcreteMediator 逻辑或创建一个新的Mediator实现。
Java 代码实现
到目前为止,我们有了清晰理念,下面我们通过代码更好理解其中概念。
示例场景
加入我们构建一个简单系统包括风扇、电源以及按钮。点击按钮能开启或关闭风扇。在我们开启风扇之前需先开电源;类似我们关闭风扇后需立刻关闭电源。
下面请看示例实现:
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,Fan同时和Button和PowerSupplier交互。这样Button类很难再重用,同时如果需要增加第二个电源至我们系统总,那么必须要修改Fan类的逻辑。
增加中介模式
下面我们实现中介模式,减少类之间的依赖,使代码更好重用。首先看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());
}
ok,测试通过。到目前为止我们已经实现了中介模式,Button, Fan, PowerSupplier类之间不再直接交互,仅和Medator引用进行交互。
如果未来我们需要增加第二个电源,仅需要更新Medator逻辑,Button, Fan类保持不变。该示例很好说明了如何分离依赖对象使代码更易维护。
什么场景下使用中介模式
如果需要处理一组紧耦合对象、难维护的代码场景,适合使用中介模式。其减少对象之间依赖和总体的复杂度。
另外,通过使用中介模式,抽出交互逻辑至单个组件,遵循单一责任原则。而且引入新的中介对象,无需修改其余对象,符合开放-闭合原则。
然而有时因为错误的设计有很多紧耦合对象,这时不应该使用中介模式,而是退回一步重新思考系统的模式。
和其他模式一样,在盲目实现中介模式之前,我们需要考虑我们的特定场景。
总结
本文我们学习了中介模式。详细解释了其能解决的问题以及什么场景下使用,然后通过示例进行对比实战学习。