0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【GoFデザインパターン】Mediator(メディエーター)パターンをJavaで理解する

0
Last updated at Posted at 2026-09-26

はじめに

本記事は、GoFデザインパターン解説シリーズの1つです。

今回は、振る舞いに関するパターンの中のMediator(メディエーター)パターンを解説します。

オブジェクト同士が「お互いを直接知りすぎている」状態を解消するパターンです。

解決したい課題

複数のオブジェクトがお互いを直接参照し合って連携する設計は、オブジェクトの数が増えるにつれて、その依存関係が網の目状(N対N)に複雑化していきます。

例えば、チャットアプリのUIコンポーネント群(入力欄・送信ボタン・文字数カウンター・送信履歴一覧)が、お互いに直接メソッドを呼び合っているとします。

「送信ボタンが押されたら、入力欄の内容を取得し、履歴一覧に追加し、入力欄をクリアし、文字数カウンターをリセットする」といった連携を、各コンポーネントが直接他のコンポーネントを参照して実装すると、コンポーネントを1つ追加・削除するたびに、関連する他の全コンポーネントの実装を見直す必要が出てきます。

Mediatorパターンは、オブジェクト同士を直接やり取りさせず、仲介役(Mediator)を1つ挟んで、すべてのやり取りをそこに集約することで、この問題を解決します。

各オブジェクトは、Mediatorとだけやり取りすればよくなります。

image.png

クラス構成

  • Mediator(メディエーター): オブジェクト間のやり取りを仲介する、共通インターフェース
  • ConcreteMediator(具体的なメディエーター): 実際の仲介ロジックを持つクラス。各Colleagueへの参照を保持する
  • Colleague(コリーグ/同僚): Mediatorを介してやり取りする、個々のオブジェクト。他のColleagueを直接は知らない

image.png

Javaでの実装例

先ほどのチャットUIの例で実装してみます。

Mediator:共通インターフェース

public interface ChatMediator {
    void notify(Component sender, String event);
}

Colleague:UIコンポーネント共通の抽象クラス

public abstract class Component {
    protected final ChatMediator mediator; // Mediatorへの参照だけを持つ(他のColleagueは知らない)

    protected Component(ChatMediator mediator) {
        this.mediator = mediator;
    }
}

ConcreteColleague:具体的なUIコンポーネント群

public class MessageInput extends Component {
    private String text = "";

    public MessageInput(ChatMediator mediator) {
        super(mediator);
    }

    public void type(String text) {
        this.text = text;
        System.out.println("[入力欄] \"" + text + "\" と入力されました");
        mediator.notify(this, "TEXT_CHANGED"); // 自分の状態変化をMediatorに通知するだけ
    }

    public String getText() {
        return text;
    }

    public void clear() {
        this.text = "";
    }
}

public class CharCounter extends Component {
    public CharCounter(ChatMediator mediator) {
        super(mediator);
    }

    public void updateCount(int count) {
        System.out.println("[文字数カウンター] " + count + "文字");
    }
}

public class SendButton extends Component {
    public SendButton(ChatMediator mediator) {
        super(mediator);
    }

    public void click() {
        System.out.println("[送信ボタン] クリックされました");
        mediator.notify(this, "SEND_CLICKED");
    }
}

public class MessageHistory extends Component {
    public MessageHistory(ChatMediator mediator) {
        super(mediator);
    }

    public void addMessage(String message) {
        System.out.println("[送信履歴] 追加: " + message);
    }
}

ConcreteMediator:実際の連携ロジックを持つクラス

public class ChatRoomMediator implements ChatMediator {
    private MessageInput input;
    private CharCounter counter;
    private SendButton sendButton;
    private MessageHistory history;

    public void setInput(MessageInput input) {
        this.input = input;
    }

    public void setCounter(CharCounter counter) {
        this.counter = counter;
    }

    public void setSendButton(SendButton sendButton) {
        this.sendButton = sendButton;
    }

    public void setHistory(MessageHistory history) {
        this.history = history;
    }

    @Override
    public void notify(Component sender, String event) {
        // どのコンポーネントから、どんなイベントが来たかに応じて、連携ロジックをここに集約する
        if (sender == input && event.equals("TEXT_CHANGED")) {
            counter.updateCount(input.getText().length());
        } else if (sender == sendButton && event.equals("SEND_CLICKED")) {
            history.addMessage(input.getText());
            input.clear();
            counter.updateCount(0);
        }
    }
}

利用側のコード

public class Main {
    public static void main(String[] args) {
        ChatRoomMediator mediator = new ChatRoomMediator();

        MessageInput input = new MessageInput(mediator);
        CharCounter counter = new CharCounter(mediator);
        SendButton sendButton = new SendButton(mediator);
        MessageHistory history = new MessageHistory(mediator);

        mediator.setInput(input);
        mediator.setCounter(counter);
        mediator.setSendButton(sendButton);
        mediator.setHistory(history);

        input.type("こんにちは");
        sendButton.click();
    }
}

実行結果:

[入力欄] "こんにちは" と入力されました
[文字数カウンター] 6文字
[送信ボタン] クリックされました
[送信履歴] 追加: こんにちは
[文字数カウンター] 0文字

image.png

MessageInput・CharCounter・SendButton・MessageHistoryは、お互いを一切直接知りません。

「入力欄が変化したらカウンターを更新する」「送信ボタンが押されたら履歴に追加し、入力欄をクリアする」といった連携ロジックはすべてChatRoomMediatorに集約されています。

新しいコンポーネント(例えば「文字数の上限警告表示」)を追加したい場合も、既存のコンポーネント同士のコードには手を入れず、Mediator側にロジックを追加するだけで済みます。

Observerパターンとの関係

Mediatorパターンは、後述するObserverパターンと組み合わせて実装されることがよくあります(上記の例では簡略化のため直接notify()を呼んでいますが、実際にはMediatorが各Colleagueのイベントを購読するObserverとして振る舞う実装も一般的です)。

両者は「複数オブジェクト間の連携を疎結合にする」という目的は共通していますが、Mediatorは「中央に連携ロジックを集約する」ことに主眼があるのに対し、Observerは「状態変化の通知の仕組み」自体に主眼がある、という違いがあります。

使用場面

  • GUIの複数コンポーネントが、複雑に連携し合うダイアログ・フォームの実装
  • 複数のオブジェクトが直接参照し合うことで、依存関係が複雑化(スパゲッティ化)している場合の整理
  • チャットルームのように、複数の参加者(オブジェクト)間のメッセージのやり取りを一元管理したい場合
  • 航空管制システム(複数の飛行機が、管制塔という仲介役を通じてのみやり取りする)のような、実世界の「仲介役」をモデル化する場合

まとめ

項目 内容
解決する課題 複数オブジェクト間の直接的な依存関係が、網の目状に複雑化してしまう
実現方法 オブジェクト同士のやり取りを、仲介役(Mediator)に一元集約する
メリット 各オブジェクトはMediatorとだけやり取りすればよく、連携ロジックの変更・追加が容易になる
関連パターン Observerパターンと組み合わせて実装されることも多い

おすすめ書籍

GoFの23パターンをより深く学びたい方には、以下の書籍がおすすめです。
Java言語のサンプルコードとUMLを使い、初心者にもわかりやすく解説されています。

Java言語で学ぶデザインパターン入門 第3版 [ 結城 浩 ]

※本リンクはアフィリエイトリンクを含みます。

参考

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?