導入
Observerは「状態変化を購読者に通知」——前章のイベントがまさにこれ。Mediatorは「多対多の複雑な連携を、仲介役1つに集約」します。オブジェクト同士の直接依存を減らすのが狙いです。
図解
flowchart TB
SUB["Subject(変化する側)"] -->|通知| O1["Observer A"]
SUB -->|通知| O2["Observer B"]
style SUB fill:#e1f5fe
サンプル
通知する側(Subject)と、通知を受け取る側(Observer)に分けます。ここでは受け取る側をラムダで登録します。
1. 通知する側(WeatherStation.cs)。誰が聞いているかを知らないまま、登録された全員に配ります。
// Observer: 気温の変化を、登録された観測者すべてに通知する
public class WeatherStation
{
private readonly List<Action<int>> _observers = new();
public void Register(Action<int> observer) => _observers.Add(observer);
public void SetTemperature(int temp)
{
foreach (var observer in _observers)
observer(temp); // 全観測者へ通知
}
}
2. 購読する側(Program.cs)。観測者を増やしてもWeatherStation.csは無変更です。
var station = new WeatherStation();
station.Register(temp => Console.WriteLine($"表示器: {temp}度"));
station.Register(temp => Console.WriteLine($"警報: {(temp >= 35 ? "猛暑" : "通常")}"));
station.SetTemperature(36);
// 表示器: 36度 / 警報: 猛暑
- Observer: 変化する側(Subject)が、購読者(Observer)へ変化を通知する。C#の
eventやActionリストで実装できる - Mediator: 部品同士が直接やり取りせず、仲介役を経由することで結合を下げる(チャットルーム等)
- どちらもオブジェクト間の直接依存を減らす
- 購読者を足しても通知側のファイルは変わらない=依存が一方向
演習
var publisher = new NewsPublisher();
publisher.Subscribe(news => Console.WriteLine($"購読者: {news}"));
publisher.Publish("速報");
// TODO: Subscribe(Action<string>) で購読者を登録し、Publish(string) で全員へ通知する
// NewsPublisher を定義してください
___
- 期待される出力:
購読者: 速報
ヒント1を見る
List<Action<string>>に登録し、Publishで全員に渡します
ヒント2を見る
class NewsPublisher { private readonly List<Action<string>> _subs = new(); public void Subscribe(Action<string> s) => _subs.Add(s); public void Publish(string news) { foreach (var s in _subs) s(news); } }
まとめ
- Observerは状態変化を購読者に通知する(イベントの一般形)
- Mediatorは多対多の連携を仲介役に集約する
- オブジェクト間の直接依存を減らす
次回: 操作の要求化と責任の連鎖Command/Chain of Responsibilityです。