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