Javaにおけるメディエーターパターン:複雑なシステムにおけるオブジェクト通信の簡素化
別名
- コントローラー
メディエーターデザインパターンの目的
メディエーターデザインパターンは、システム内の複数のオブジェクトまたはクラス間の通信の複雑さを軽減することを目的としています。これは、異なるクラス間の相互作用を処理する集中型のメディエータークラスを提供することで実現され、それによって互いに直接依存することを軽減します。
実世界の例を用いたメディエーターパターンの詳細な説明
実世界の例
混雑した空港の航空交通管制システムを想像してみてください。航空交通管制官はメディエーターとして機能します。このシナリオでは、多数の航空機が空港の空域で離陸、着陸、または航行することを希望しています。混乱や事故につながる可能性のある、各パイロットが他のすべてのパイロットと直接通信する代わりに、すべての通信は航空交通管制官を介して行われます。管制官は要求を受信し、処理し、各パイロットに明確で整理された指示を出します。この集中型システムは、通信の複雑さを軽減し、空港の運用を管理する際の安全性と効率を確保します。これは、ソフトウェアのメディエーターデザインパターンに類似しており、中央のメディエータークラスが異なるオブジェクトまたはシステム間の相互作用を処理および調整します。
簡単な言葉で
メディエーターは、通信フローを仲介オブジェクトに強制することにより、一連のクラスを分離します。
Wikipediaによると
ソフトウェア工学では、メディエーターパターンは、オブジェクトのセットがどのように相互作用するかをカプセル化するオブジェクトを定義します。このパターンは、プログラムの実行動作を変更できるため、振る舞いパターンと見なされます。オブジェクト指向プログラミングでは、プログラムは多くのクラスで構成されることがよくあります。ビジネスロジックと計算はこれらのクラスに分散されます。ただし、特にメンテナンスやリファクタリング中にプログラムにクラスが追加されると、これらのクラス間の通信の問題がより複雑になる可能性があります。これにより、プログラムの読み取りと保守が困難になります。さらに、変更が他のいくつかのクラスのコードに影響を与える可能性があるため、プログラムの変更が困難になる可能性があります。メディエーターパターンを使用すると、オブジェクト間の通信はメディエーターオブジェクト内にカプセル化されます。オブジェクトは互いに直接通信するのではなく、メディエーターを介して通信します。これにより、通信するオブジェクト間の依存関係が軽減され、結合が減少します。
Javaにおけるメディエーターパターンのプログラム例
この例では、メディエーターはオブジェクトのセットがどのように相互作用するかをカプセル化します。互いに直接参照する代わりに、メディエーターインターフェースを使用します。
パーティーメンバーの `Rogue`、`Wizard`、`Hobbit`、`Hunter` はすべて、`PartyMember` インターフェースを実装する `PartyMemberBase` を継承しています。
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におけるメディエーターパターンの実際のアプリケーション
- java.util.Timer のすべての scheduleXXX() メソッド
- java.util.concurrent.Executor#execute()
- java.util.concurrent.ExecutorService の submit() および invokeXXX() メソッド
- java.util.concurrent.ScheduledExecutorService の scheduleXXX() メソッド
- java.lang.reflect.Method#invoke()
- Java Message Service(JMS)は、クライアントとサーバー間のメッセージ交換を処理するためにメディエーターを使用します。
- JavaBeansプロパティ変更サポートクラス(java.beans.PropertyChangeSupport)は、プロパティ変更に関するBean間の通信を処理することにより、メディエーターとして機能します。
メディエーターパターンの利点と欠点
利点
- プログラムのコンポーネント間の結合を減らし、より良い組織化とより簡単なメンテナンスを促進します。
- 制御の集中化。メディエーターパターンは制御ロジックを集中化するため、理解と管理が容易になります。
欠点
- メディエーターは、システム内のすべてのクラスと結合されたgod objectになり、責任と複雑さが大きくなりすぎる可能性があります。
関連するJavaデザインパターン
- オブザーバー:メディエーターパターンは、オブザーバーパターンを使用して状態変更についてさまざまなオブジェクトに通知できるため、一緒に使用されることがよくあります。メディエーターは、オブザーバーによって管理される通信チャネルとして効果的に機能します。
- ファサード:メディエーターは、ファサードがサブシステムインターフェースを簡素化する方法と同様に、コンポーネント間の通信を簡素化しますが、メディエーターの同僚はメディエーターに通信することができます。
- コマンド:コマンドは、受信者にディスパッチされるときに仲介され、リクエストをオブジェクトとしてカプセル化できます。