Java 中的调解器模式:简化复杂系统中的对象通信
也称为
- 控制器
调解器设计模式的意图
调解器设计模式旨在降低系统中多个对象或类之间通信的复杂性。它通过提供一个集中式调解器类来处理不同类之间的交互来实现这一点,从而减少它们彼此之间的直接依赖关系。
带现实世界示例的调解器模式详细解释
现实世界的例子
想象一个繁忙机场的空中交通管制系统,其中空中交通管制员充当调解器。在这种情况下,许多飞机希望起飞、降落或在机场空域周围航行。而不是让每个飞行员直接与其他每个飞行员进行沟通,这会导致混乱和潜在的事故,所有沟通都通过空中交通管制员进行。管制员接收请求,处理它们,并向每个飞行员发出清晰、有条理的指示。这种集中式系统降低了通信的复杂性,并确保了管理机场运营的安全性和效率。这类似于软件中的调解器设计模式,其中一个中央调解器类处理和协调不同对象或系统之间的交互。
简单来说
调解器通过强制它们的通信流经一个调解对象来解耦一组类。
维基百科说
在软件工程中,调解器模式定义一个对象,它封装了一组对象如何交互。由于它可以改变程序运行的行为,因此这种模式被认为是行为模式。在面向对象编程中,程序通常由许多类组成。业务逻辑和计算分布在这些类中。但是,随着程序中添加了更多类,尤其是在维护和/或重构期间,这些类之间的通信问题可能会变得更加复杂。这使得程序更难阅读和维护。此外,更改程序可能会变得很困难,因为任何更改都可能会影响其他几个类的代码。使用调解器模式,对象之间的通信被封装在调解器对象中。对象不再直接相互通信,而是通过调解器进行通信。这减少了通信对象之间的依赖关系,从而减少了耦合。
Java 中调解器模式的编程示例
在这个例子中,调解器封装了一组对象如何交互。它们不直接引用彼此,而是使用调解器接口。
队伍成员 `Rogue`、`Wizard`、`Hobbit` 和 `Hunter` 都继承自 `PartyMemberBase`,实现了 `PartyMember` 接口。
public interface PartyMember {
void joinedParty(Party party);
void partyAction(Action action);
void act(Action action);
}
@Slf4j
public abstract class PartyMemberBase implements PartyMember {
protected Party party;
@Override
public void joinedParty(Party party) {
LOGGER.info("{} joins the party", this);
this.party = party;
}
@Override
public void partyAction(Action action) {
LOGGER.info("{} {}", this, action.getDescription());
}
@Override
public void act(Action action) {
if (party != null) {
LOGGER.info("{} {}", this, action);
party.act(this, action);
}
}
@Override
public abstract String toString();
}
public class Rogue extends PartyMemberBase {
@Override
public String toString() {
return "Rogue";
}
}
// Wizard, Hobbit, and Hunter are implemented similarly
我们的调解器系统由 `Party` 接口及其实现组成。
public interface Party {
void addMember(PartyMember member);
void act(PartyMember actor, Action action);
}
public class PartyImpl implements Party {
private final List<PartyMember> members;
public PartyImpl() {
members = new ArrayList<>();
}
@Override
public void act(PartyMember actor, Action action) {
for (var member : members) {
if (!member.equals(actor)) {
member.partyAction(action);
}
}
}
@Override
public void addMember(PartyMember member) {
members.add(member);
member.joinedParty(this);
}
}
这是一个展示调解器模式在实际中的示例。
public static void main(String[] args) {
// create party and members
Party party = new PartyImpl();
var hobbit = new Hobbit();
var wizard = new Wizard();
var rogue = new Rogue();
var hunter = new Hunter();
// add party members
party.addMember(hobbit);
party.addMember(wizard);
party.addMember(rogue);
party.addMember(hunter);
// perform actions -> the other party members
// are notified by the party
hobbit.act(Action.ENEMY);
wizard.act(Action.TALE);
rogue.act(Action.GOLD);
hunter.act(Action.HUNT);
}
这是运行示例时控制台的输出。
14:05:15.081 [main] INFO com.iluwatar.mediator.PartyMemberBase -- Hobbit joins the party
14:05:15.083 [main] INFO com.iluwatar.mediator.PartyMemberBase -- Wizard joins the party
14:05:15.083 [main] INFO com.iluwatar.mediator.PartyMemberBase -- Rogue joins the party
14:05:15.083 [main] INFO com.iluwatar.mediator.PartyMemberBase -- Hunter joins the party
14:05:15.083 [main] INFO com.iluwatar.mediator.PartyMemberBase -- Hobbit spotted enemies
14:05:15.083 [main] INFO com.iluwatar.mediator.PartyMemberBase -- Wizard runs for cover
14:05:15.083 [main] INFO com.iluwatar.mediator.PartyMemberBase -- Rogue runs for cover
14:05:15.083 [main] INFO com.iluwatar.mediator.PartyMemberBase -- Hunter runs for cover
14:05:15.083 [main] INFO com.iluwatar.mediator.PartyMemberBase -- Wizard tells a tale
14:05:15.083 [main] INFO com.iluwatar.mediator.PartyMemberBase -- Hobbit comes to listen
14:05:15.083 [main] INFO com.iluwatar.mediator.PartyMemberBase -- Rogue comes to listen
14:05:15.083 [main] INFO com.iluwatar.mediator.PartyMemberBase -- Hunter comes to listen
14:05:15.083 [main] INFO com.iluwatar.mediator.PartyMemberBase -- Rogue found gold
14:05:15.083 [main] INFO com.iluwatar.mediator.PartyMemberBase -- Hobbit takes his share of the gold
14:05:15.083 [main] INFO com.iluwatar.mediator.PartyMemberBase -- Wizard takes his share of the gold
14:05:15.083 [main] INFO com.iluwatar.mediator.PartyMemberBase -- Hunter takes his share of the gold
14:05:15.083 [main] INFO com.iluwatar.mediator.PartyMemberBase -- Hunter hunted a rabbit
14:05:15.083 [main] INFO com.iluwatar.mediator.PartyMemberBase -- Hobbit arrives for dinner
14:05:15.083 [main] INFO com.iluwatar.mediator.PartyMemberBase -- Wizard arrives for dinner
14:05:15.083 [main] INFO com.iluwatar.mediator.PartyMemberBase -- Rogue arrives for dinner
带现实世界示例的调解器模式详细解释
何时在 Java 中使用调解器模式
在以下情况下使用调解器模式
- 一组对象以定义明确但复杂的方式进行通信。由此产生的相互依赖关系是无结构的,难以理解
- 重用一个对象很困难,因为它引用并与许多其他对象进行通信
- 分布在多个类之间的行为应该可以自定义,而不需要大量子类化
Java 中调解器模式的现实世界应用
- 所有 `scheduleXXX()` 方法的 java.util.Timer
- java.util.concurrent.Executor#execute()
- 提交() 和 invokeXXX() 方法的 java.util.concurrent.ExecutorService
- `scheduleXXX()` 方法的 java.util.concurrent.ScheduledExecutorService
- java.lang.reflect.Method#invoke()
- Java 消息服务 (JMS) 使用调解器来处理客户端和服务器之间的消息交换。
- JavaBeans 属性更改支持类 (java.beans.PropertyChangeSupport) 充当调解器,通过处理有关属性更改的 bean 之间的通信来实现这一点。
调解器模式的优缺点
优点
- 减少程序组件之间的耦合,促进更好的组织和更轻松的维护。
- 集中控制。调解器模式集中了控制逻辑,使其更容易理解和管理。
权衡
- 调解器可能会变成一个与系统中所有类耦合的上帝对象,承担太多责任和复杂性。
相关的 Java 设计模式
- 观察者:通常一起使用,其中调解器模式可以使用观察者模式来通知各种对象有关状态更改的信息。调解器实际上充当由观察者管理的通信渠道。
- 外观:调解器简化了组件之间的通信,类似于外观简化子系统接口的方式,但调解器的同事可以与调解器进行回传。
- 命令:命令可以在分派到接收者时进行调解,将请求封装为一个对象。