#概要
前回は、飼いねこと野良ねこの2匹を用いて、Observer パターンの構造を説明しました。今回はObserver.update 関数を中心に、にゃんこがごはんだけでなく他のものをねだるようになります。前回の内容を前提として解説いたしますので、先にそちらをご覧ください。
#登場するにゃんこ
飼い猫のタマ
タマは、マンションの3階で暮らしています。飼い主は一人暮らしです。
飼い猫のモモ
最近、タマと同じ家に住むようになりました。
#ごはんだけでは満足できないタマ
タマが飼い主におねだりするのは、ごはんだけではありません。遊んでほしかったりマタタビが気になったりします。
飼い主にどのお願いをしているかを伝える方法は、おおまかに2つあります。引数を介して渡すPush型と、引数を介さないで(その他の方法を用いて)渡すPull型です。
前回のコードは引数がなかったため、Pull型に分類されます。引数を受け取る必要がない処理の場合はPull型を用いるといいでしょう。もしPull型で必要な情報がある場合は、Observer クラスが集めたり、自身が知っているものを用いたりします。
一方、Push型では引数に、文字列や数値、Event クラス(後述)などを渡します。
#飼い主にお願いを伝える
まずは、様々なおねだりをできるようにするために「お願い」をクラスにします。
public abstract class Request{// Event クラス
public abstract void words();
}
public class Food extends Request{// Event クラス
@Overide
public void words(){
System.out.println("にゃー(おなかすいた)");
}
}
public class Playing extends Request{// Event クラス
@Overide
public void words(){
System.out.println("にゃー(ひまー)");
}
}
public class Matatabi extends Request{// Event クラス
@Overide
public void words(){
System.out.println("にゃー(マタタビほしい!)");
}
}
Event クラスを渡す
次の例はPush型で、Request クラス(=Event クラス) を引数にしたコードです。
public class Cat{// Subject クラス
private Human human;
public void setHuman(Human human){// setObserver()
this.human = human;
}
public void hungry(){// notifyObservers()
this.human.called(new Food());
}
public void killTime(){// notifyObservers()
this.human.called(new Playing());
}
public void wantMatatabi(){// notifyObservers()
this.human.called(new Matatabi());
}
}
public class Human{// Observer クラス
public void called(Request request){// notify() or update()
request.words();
String className = request.getClass().getName();
if(className.equals(Food.class.getName())){
System.out.println("カリカリをあげる");
} else if(className.equals(killTime.class.getName())) {
System.out.println("もう、しょうがないなー(ねこじゃらしフリフリ)");
} else if(className.equals(Matatabi.class.getName())) {
System.out.println("マタタビをあげる");
}
}
}
public static void main(String[] args) {
Cat tama = new Cat();
Human master = new Human();
tama.setHuman(master);
tama.hungry();
tama.killTime();
tama.wantMatatabi();
}
にゃー(おなかすいた)
カリカリをあげる
にゃー(ひまー)
もう、しょうがないなー(ねこじゃらしフリフリ)
にゃー(マタタビほしい!)
マタタビをあげる
Subject クラス自身(this)を渡す
よく渡す値として、呼び出し元のSubject クラス(=Cat クラス)自身もあります。Observer クラス(=Human クラス)が複数のSubject クラスから呼び出される場合、呼び出し元が分かるため便利です。
public class Cat{// Subject クラス
private Human human;
private Request request;
public final String name;
public Cat(String name){
this.name = name;
}
public void setHuman(Human human){// setObserver()
this.human = human;
}
public void hungry(){// notifyObservers()
request = new Food();
this.human.called(this);
}
public void killTime(){// notifyObservers()
request = new Playing();
this.human.called(this);
}
public void wantMatatabi(){// notifyObservers()
request = new Matatabi();
this.human.called(this);
}
public Request getRequest(){
return request;
}
}
public class Human{// Observer クラス
public void called(Cat cat){// notify() or update()
cat.getRequest().words();
String className = cat.getRequest().getClass().getName();
if(className.equals(Food.class.getName())){
System.out.println(cat.name + "にカリカリをあげる");
} else if(className.equals(killTime.class.getName())) {
System.out.println("もう、しょうがないなー(ねこじゃらしフリフリ)");
} else if(className.equals(Matatabi.class.getName())) {
System.out.println(cat.name + "にマタタビをあげる");
}
}
}
public static void main(String[] args) {
Cat tama = new Cat("タマ");
Cat momo = new Cat("モモ");
Human master = new Human();
tama.setHuman(master);
momo.setHuman(master);
tama.hungry();
tama.killTime();
momo.hungry();
tama.wantMatatabi();
}
にゃー(おなかすいた)
タマにカリカリをあげる
にゃー(ひまー)
もう、しょうがないなー(ねこじゃらしフリフリ)
にゃー(おなかすいた)
モモにカリカリをあげる
にゃー(マタタビほしい!)
タマにマタタビをあげる
Java の Observer クラスでは、呼び出し元のSubject クラス(Java内ではObservable クラスという名前)と、Object 全般を引数で受け取れるようになっています。
#おわりに
Push型とPull型のどちらを用いるかは、私もまだはっきりとしたことは言えません(勉強中)。ぜひ参考資料をご覧になってください。
前回はたくさんの「いいね」をいただけてとても嬉しかったです。ありがとうございます。普段見ているqiitaランキングに前回の記事が載っていて、かなり驚きました(思わずスクショを撮りました)。この記事も皆さまのお役に立てば幸いです。
#参考資料
[1][https://qiita.com/varmil/items/8cd8fe9da510e31d940a]
[2][http://d.hatena.ne.jp/backpaper0/20111111/1321012118]
[3][http://apsec99-www.se.cs.titech.ac.jp/local/material/design-patterns/resources/19.html]