Observerパターン
状態の変化を通知する
ポイント
* インターフェイス(下記の例では、IObserver)および更新したいデータ群のクラス(MoneyData)を用意する。なお、インターフェイスには、このクラスを引数にもつ更新用のメソッド(Update(MoneyData moneyData))を追加する。 * 通知したいクラス(Form1, Form2)に、上記のインターフェイスを継承させる。Update()には更新されてくるデータが来るので、その結果を反映させる処理を実装しておく * 更新させるクラス(Task)に、インターフェイスのリスト(IList<IObserver> observers)を用意しておき、通知したいクラスのインスタンスをリストに追加しておく。そのインスタンスの更新メソッド(observer.Update())に対して、データを通知する
サンプル
IObserver.cs
* このインターフェイスがキモ!!!public interface IObserver { void Update(MoneyData moneyData); }
MoneyData.cs
public class MoneyData { public int Yen { get; set; } public int Euro { get; set; } }
Task.cs
public class Task { MoneyData money; IList<IObserver> observers; Random random = new System.Random(); public Task(Form1 form1, Form2 form2) { this.money = new MoneyData(); this.observers = new List<IObserver> { form1, form2, }; this.random = new Random(); } public void Execute() { foreach(var observer in this.observers) { observer.Update(this.FakeData()); } } private MoneyData FakeData() { this.money.Yen = this.random.Next(50, 200); this.money.Euro = this.random.Next(1, 3); return this.money; } }
Form1.cs
public partial class Form1 : Form, IObserver { private const int IintervalTime = 1000; private bool IsAlive = false; private Series series1; private Series series2; private int count = 0; public Form1() { InitializeComponent(); this.chart1.Series.Clear(); string yenMarketText = "円相場"; string euroMarketText = "ユーロ相場"; this.series1 = new Series(yenMarketText); this.series1.ChartType = SeriesChartType.FastPoint; this.series2 = new Series(euroMarketText); this.series2.ChartType = SeriesChartType.FastPoint; ChartArea area = new ChartArea(); area.AxisX.Minimum = 0; area.AxisX.Maximum = 100000; area.AxisY.Minimum = 0; area.AxisY.Maximum = 500; this.chart1.ChartAreas.Add(area); this.chart1.Series.Add(this.series1); this.chart1.Series.Add(this.series2); } public void Update(MoneyData moneyData) { this.series1.Points.AddXY(this.count, moneyData.Yen); this.series2.Points.AddXY(this.count, moneyData.Euro); } // Startボタン private void button1_Click(object sender, EventArgs e) { this.IsAlive = true; Form2 form2 = new Form2(); form2.Show(); Task task = new Task(this, form2); var time = 0; var oldTime = Environment.TickCount; while (this.Created) { if (!this.IsAlive) { form2.Close(); return; } time++; if (oldTime + IintervalTime <= Environment.TickCount) { task.Execute(); oldTime = Environment.TickCount; time = 0; } Application.DoEvents(); } } // Stopボタン private void button2_Click(object sender, EventArgs e) { this.IsAlive = false; } }
Form2.cs
public partial class Form2 : Form, IObserver { public Form2() { InitializeComponent(); } public void Update(MoneyData moneyData) { this.label1.Text = string.Format("1ドル:約{0}円", moneyData.Yen); this.label2.Text = string.Format("1ドル:約{0}ユーロ", moneyData.Euro); } }
補足
* 今回のサンプルでは、Formに対して、通知したが、ログ出力するクラスなどに対しても使える
参考資料
http://journal.mycom.co.jp/column/objc/109/index.htmlhttp://gushwell.ifdef.jp/dp/observer.html
http://hccweb1.bai.ne.jp/tsune-1/CSharp/observer.html
関連記事
Observerパターン ~IObserver / IObservable インターフェース~
* C#には、IObserver / IObservable インターフェースがある。詳細は以下を参照。http://blogs.yahoo.co.jp/dk521123/23250342.html