@ITの掲示板で、こんな記事を見かけたのでちょびっと書いてみる。
デザインパターンの中でも、割と有名(だと思ってる)Observerパターンについて。
まずは、Javaから。
Javaには標準で、java.util.Observableクラスとjava.util.Observerインターフェースがある。
これを使うのが手っ取り早い。
今回の例題は、Personクラスがあって、Nameプロパティを変更すると、「Person Name ~」と表示するようなものです。
んじゃ早速Personクラスから。
package com.wankuma.kazuki.observerpattern;
import java.util.Observable;
// Observableを継承する。
public class Person extends Observable {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
if (this.name == name) {
return;
}
this.name = name;
// 変更があったというフラグを立てて、Observerに変更を通知する。
setChanged();
notifyObservers();
}
}
setNameで変更があったことをsetChangedとnotifyObserversでObserverに対して通知してます。
Javaではご法度のStringの==による比較をやってるけど、値が違う場合にはnotifyObserversしないというの実現するってのをequalsメソッドつかってやるとnullとかも考えなきゃなのでメンドクサイ。
なので、==を使ってお茶を濁してる。
Observer側のPersonPrinterのコードもさくっと実装。
package com.wankuma.kazuki.observerpattern;
import java.util.Observable;
import java.util.Observer;
public class PersonPrinter implements Observer {
public void update(Observable o, Object arg) {
Person p = (Person) o;
System.out.println("Person Name:" + p.getName());
}
}
System.out.printlnで表示してるだけになる。
んじゃ、この2つのクラスを組み合わせて使うMainクラスを見てみよう。
package com.wankuma.kazuki.observerpattern;
public class Main {
public static void main(String[] args) {
// PersonとPrinterを組み立てる
Person p = new Person();
PersonPrinter pp = new PersonPrinter();
p.addObserver(pp);
p.setName("田中 太郎");
p.setName("田中 一郎");
}
}
実行すると
田中 太郎
田中 一郎
と表示される。
ちゃんと、監視できてるね。
Rubyにも同じようなクラスが標準であるので同じような感じのコードでいける。
require 'observer'
class Person
include Observable
attr_accessor :name
def name=(name)
return if @name == name
@name = name
changed
notify_observers(self)
end
end
class PersonPrinter
def update(obj)
puts "Person Name:" + obj.name
end
end
p = Person.new
pp = PersonPrinter.new
p.add_observer(pp)
p.name = "田中 太郎"
p.name = "田中 一郎"
changedで変更フラグを立ててnotify_observersで通知をする。全く同じ。
さて、お次はC#!
こいつだけは、標準でObserverクラスとかを持ってない。
そのかわり、DelegateやEventという仕組みを言語として持ってたりする。その仕組みを使うとこんな感じかな。
using System;
namespace Com.Wankuma.Kazuki.ObserverPattern
{
public class Person
{
// 変更通知イベント
public event EventHandler NameChanged;
// 変更通知をするメソッド
protected void OnNameChanged()
{
if (NameChanged != null)
{
NameChanged(this, EventArgs.Empty);
}
}
private string _name;
public string Name
{
get { return _name; }
set
{
if (_name == value)
{
return;
}
_name = value;
OnNameChanged();
}
}
}
class Program
{
static void Main(string[] args)
{
var p = new Person();
// 表示するだけだから、いちいちクラスこさえなくてもいいや
p.NameChanged += (sender, e) => Console.WriteLine("Person Name: " + p.Name);
p.Name = "田中 太郎";
p.Name = "田中 一郎";
}
}
}
三者三様だね。(似てるけど)