1. パターンの意図
メディエータ(Mediator)パターン は、
複数オブジェクト間の複雑な依存関係を「仲介者(Mediator)」に集約して、疎結合にする デザインパターンです。
解決する問題
- 多数のオブジェクトが相互に直接やり取りすると依存関係がスパゲッティ化する
- 各コンポーネントが「誰に通知すべきか」を知りすぎると保守が難しい
- 連携のルールを一箇所にまとめたい
ポイント
- Mediator:仲介インターフェース(コンポーネント間の調停役)
- ConcreteMediator:通信ルールを実装
- Colleague:やり取りするコンポーネント(Mediator 経由で会話する)
- オブジェクト間の直接依存をなくし、Mediator に一元化する
2. UML 図
3. Flutter / Dart 実装例
Mediator インターフェース
abstract class Mediator {
void notify(Colleague sender, String event);
}
Colleague(参加者)
abstract class Colleague {
Mediator mediator;
Colleague(this.mediator);
void send(String event) {
mediator.notify(this, event);
}
void receive(String event);
}
具体的な Colleague
class Button extends Colleague {
Button(Mediator mediator) : super(mediator);
void click() => send("click");
@override
void receive(String event) {
print("Button received: $event");
}
}
class TextBox extends Colleague {
TextBox(Mediator mediator) : super(mediator);
void input(String text) => send("input:$text");
@override
void receive(String event) {
print("TextBox received: $event");
}
}
ConcreteMediator
class UIControlMediator implements Mediator {
late Button button;
late TextBox textBox;
@override
void notify(Colleague sender, String event) {
if (sender == button && event == "click") {
textBox.receive("Button clicked → clear text");
} else if (sender == textBox && event.startsWith("input:")) {
button.receive("TextBox changed → enable button");
}
}
}
利用例
void main() {
final mediator = UIControlMediator();
final button = Button(mediator);
final textBox = TextBox(mediator);
mediator.button = button;
mediator.textBox = textBox;
textBox.input("Hello"); // Button に通知される
button.click(); // TextBox に通知される
}
4. Android / Kotlin 実装例
Mediator
interface Mediator {
fun notify(sender: Colleague, event: String)
}
Colleague
abstract class Colleague(val mediator: Mediator) {
fun send(event: String) {
mediator.notify(this, event)
}
abstract fun receive(event: String)
}
具体的な Colleague
class Button(mediator: Mediator) : Colleague(mediator) {
fun click() = send("click")
override fun receive(event: String) {
println("Button received: $event")
}
}
class TextBox(mediator: Mediator) : Colleague(mediator) {
fun input(text: String) = send("input:$text")
override fun receive(event: String) {
println("TextBox received: $event")
}
}
ConcreteMediator
class UIControlMediator : Mediator {
lateinit var button: Button
lateinit var textBox: TextBox
override fun notify(sender: Colleague, event: String) {
when {
sender == button && event == "click" ->
textBox.receive("Button clicked → clear text")
sender == textBox && event.startsWith("input:") ->
button.receive("TextBox changed → enable button")
}
}
}
利用例
fun main() {
val mediator = UIControlMediator()
val button = Button(mediator)
val textBox = TextBox(mediator)
mediator.button = button
mediator.textBox = textBox
textBox.input("Hello") // → Button received
button.click() // → TextBox received
}
5. 実務ユースケース
Flutter
- 複数 Widget 間の調整を一箇所に集約(フォーム入力 → ボタン状態変更)
- Bloc / Provider での「イベント仲介」的役割
- Dialog / Form の入力値チェックと連携制御
Android / Kotlin
- DialogFragment ↔ Activity 間の通信を Mediator 化
- UI コンポーネント間の連携をまとめる(ボタン → 入力フォーム → エラーメッセージ)
- Chat や Pub/Sub の仲介役
6. メリット / デメリット
メリット
- 依存関係が一箇所に集約 → 各コンポーネントはシンプル
- 複数オブジェクト間の相互依存を減らせる
- 連携ルールを一元的に管理できる
デメリット
- Mediator に処理が集中し「神オブジェクト化」するリスク
- 単純なケースでは逆に複雑化する
まとめ
- Mediator パターンは「複雑な相互依存を一箇所にまとめる」設計
- Flutter/Android では UI コンポーネント間の制御やイベント連携に便利
- Observer = 1対多の通知 / Mediator = 多対多の調停 と整理すると理解しやすい