The Mediator Pattern in Java – Java中的调解器模式

最后修改: 2019年 4月 1日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

In this article, we’ll have a look at the Mediator Pattern, one of the GoF behavioral patterns. We’ll describe its purpose and explain when we should use it.

在这篇文章中,我们将看看调解人模式,这是GoF行为模式之一。我们将描述它的目的,并解释何时应该使用它。

As usual, we’ll also provide a simple code example.

像往常一样,我们还将提供一个简单的代码例子。

2. Mediator Pattern

2.调解员模式

In object-oriented programming, we should always try to design the system in such a way that components are loosely coupled and reusable. This approach makes our code easier to maintain and test.

在面向对象的编程中,我们应该始终尝试以这样的方式设计系统,即组件是松散耦合和可重用的。这种方法使我们的代码更容易维护和测试。

In real life, however, we often need to deal with a complex set of dependent objects. This is when the Mediator Pattern may come in handy.

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

The intent of the Mediator Pattern is to reduce the complexity and dependencies between tightly coupled objects communicating directly with one another. This is achieved by creating a mediator object that takes care of the interaction between dependent objects. Consequently, all the communication goes through the mediator.

调解器模式的目的是减少紧密耦合的对象之间直接通信的复杂性和依赖性。这是通过创建一个调解器对象来实现的,该对象负责处理依赖对象之间的交互。因此,所有的通信都要通过调解器。

This promotes loose coupling, as a set of components working together no longer have to interact directly. Instead, they only refer to the single mediator object. This way, it is also easier to reuse these objects in other parts of the system.

这促进了松散耦合,因为一组一起工作的组件不再需要直接互动。相反,它们只参考单一的中介对象。这样一来,在系统的其他部分重用这些对象也就更容易了。

3. Mediator Pattern’s UML Diagram

3.调解器模式的UML图示

Let’s now look at the pattern visually:

现在让我们从视觉上看一下这个模式。

mediator

In the above UML diagram, we can identify the following participants:

在上述UML图中,我们可以确定以下参与者。

  • Mediator defines the interface the Colleague objects use to communicate
  • Colleague defines the abstract class holding a single reference to the Mediator
  • ConcreteMediator encapsulates the interaction logic between Colleague objects
  • ConcreteColleague1 and ConcreteColleague2 communicate only through the Mediator

As we can see, Colleague objects do not refer to each other directly. Instead, all the communication is carried out by the Mediator.

我们可以看到,Colleague对象并不直接引用对方。相反,所有的通信是由Mediator进行的。

Consequently, ConcreteColleague1 and ConcreteColleague2 can be more easily reused.

因此,ConcreteColleague1ConcreteColleague2可以更容易地重复使用。

Also, in case we need to change the way Colleague objects work together, we only have to amend the ConcreteMediator logic. Or we can create a new implementation of the Mediator.

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

4. Java Implementation

4.Java实现

Now that we have a clear idea of the theory, let’s take look at an example to better understand the concept in practice.

现在我们对理论有了一个清晰的概念,让我们看一个例子来更好地理解这个概念的实践。

4.1. Example Scenario

4.1.示例场景

Imagine we’re building a simple cooling system that consists of a fan, a power supply, and a button. Pressing the button will either turn on or turn off the fan. Before we turn the fan on, we need to turn on the power. Similarly, we have to turn off the power right after the fan is turned off.

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

Let’s now take a look at the example implementation:

现在让我们来看看这个例子的实现。

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
    }
}

Next, let’s test the functionality:

接下来,让我们测试一下功能。

@Test
public void givenTurnedOffFan_whenPressingButtonTwice_fanShouldTurnOnAndOff() {
    assertFalse(fan.isOn());

    button.press();
    assertTrue(fan.isOn());

    button.press();
    assertFalse(fan.isOn());
}

Everything seems to work fine. But notice how Button, Fan, and PowerSupplier classes are tightly coupled. The Button operates directly on the Fan and the Fan interacts with both Button and PowerSupplier.

一切似乎都很正常。但是请注意Button、Fan、PowerSupplier类是如何紧密耦合的Button直接对Fan进行操作,而Fan则与ButtonPowerSupplier.相互作用。

It would be hard to reuse the Button class in other modules. Also, if we need to add a second power supply into our system, then we would have to modify the Fan class’ logic.

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

4.2. Adding the Mediator Pattern

4.2.添加调解人模式

Now, let’s implement the Mediator Pattern to reduce the dependencies between our classes and make the code more reusable.

现在,让我们来实现调解器模式,以减少我们的类之间的依赖性,并使代码更加可重复使用。

First, let’s introduce the Mediator class:

首先,我们来介绍一下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();
    }
}

Next, let’s modify the remaining classes:

接下来,我们来修改其余的类。

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();
    }
}

Again, let’s test the functionality:

再次,让我们测试一下功能。

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

Our cooling system works as expected.

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

Now that we’ve implemented the Mediator Pattern, none of the Button, Fan, or PowerSupplier classes communicate directly. They only have a single reference to the Mediator.

现在我们已经实现了调解器模式,ButtonFanPowerSupplier类都没有直接通信。它们只有一个对Mediator的引用。

If we need to add a second power supply in the future, all we have to do is to update Mediator’s logic; Button and Fan classes remain untouched.

如果我们将来需要添加第二个电源,我们所要做的就是更新Mediator的逻辑;ButtonFan类保持不动。

This example shows how easily we can separate dependent objects and make our system easier to maintain.

这个例子表明我们可以很容易地分离依赖对象,使我们的系统更容易维护。

5. When to Use the Mediator Pattern

5.何时使用调解人模式

The Mediator Pattern is a good choice if we have to deal with a set of objects that are tightly coupled and hard to maintain. This way we can reduce the dependencies between objects and decrease the overall complexity.

如果我们必须处理一组紧密耦合且难以维护的对象,那么调解器模式是一个不错的选择。这样,我们可以减少对象之间的依赖关系,降低整体的复杂性。

Additionally, by using the mediator object, we extract the communication logic to the single component, therefore we follow the Single Responsibility Principle. Furthermore, we can introduce new mediators with no need to change the remaining parts of the system. Hence, we follow the Open-Closed Principle.

此外,通过使用调解器对象,我们将通信逻辑提取到单一组件中,因此我们遵循单一责任原则。此外,我们可以引入新的调解器,而不需要改变系统的其余部分。因此,我们遵循 “开放-封闭原则”。

Sometimes, however, we may have too many tightly coupled objects due to the faulty design of the system. If this is a case, we should not apply the Mediator Pattern. Instead, we should take one step back and rethink the way we’ve modeled our classes.

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

As with all other patterns, we need to consider our specific use case before blindly implementing the Mediator Pattern.

与所有其他模式一样,在盲目地实现调解器模式之前,我们需要考虑我们的具体使用情况

6. Conclusion

6.结语

In this article, we learned about the Mediator Pattern. We explained what problem this pattern solves and when we should actually consider using it. We also implemented a simple example of the design pattern.

在这篇文章中,我们了解了调解人模式。我们解释了这种模式解决了什么问题,以及什么时候我们应该真正考虑使用它。我们还实现了该设计模式的一个简单例子。

As always, the complete code samples are available over on GitHub.

一如既往,完整的代码样本可在GitHub上获得over