#前回やったやつ
デザインパターン入門 〜Strategyパターン〜
#Observerパターンってどんなの?
データを変更する。→処理1をする。処理2をする・・・処理nをするって場合に使います。
ただし、処理は増えたり減ったりちょっと実装が違ったりする。
共通なのは「データが変わったら実行される」という点です。
今回は「半丁」を実装しました。サイコロを2個振って合計が偶数か奇数か当てるゲームです。
#実装
package diceGame;
public class PlayGame {
public static void main(String[] args) {
Game game = new Game();
Player p1 = new Player("半次郎",1);
Player p2 = new Player("丁乃助",0);
// プレイヤーの登録
game.addObserver(p1);
game.addObserver(p2);
// ゲームの実行
int d1 = dice();
int d2 = dice();
game.throwDices(d1, d2);
// プレイヤー抜ける。
System.out.println("用事を思い出したので帰らせていただきやす。");
game.deleteObserver(p1);
// プレイヤー追加
System.out.println("お、やってる。やってる。");
Charlatan p3 = new Charlatan("イカ政");
game.addObserver(p3);
//ゲームの実行
d1 = dice();
d2 = dice();
game.throwDices(d1, d2);
}
/**
* サイコロを振る
* @return dice
*/
private static int dice(){
int dice = (int)(Math.random() * 6) + 1;
System.out.println("サイコロの目 :"+dice);
return dice;
}
}
package diceGame;
import java.util.Observable;
public class Game extends Observable{
private int diceTotalValue;
/**
* 親がサイコロを振ったことをプレイヤーに通知する。
* @param dice1
* @param dice2
*/
public void throwDices(int dice1, int dice2){
System.out.println("丁半揃いました。よござんすね?");
this.diceTotalValue = dice1 + dice2;
setChanged();
notifyObservers();
}
/**
* サイコロの合計
* @return
*/
public int getDiceTotalValue(){
return diceTotalValue;
}
}
package diceGame;
import java.util.Observable;
import java.util.Observer;
public class Player implements Observer {
private String playerName;
private int evenOrOdd;
/**
* プレイヤーの設定
* @param playerName
* @param evenOrOdd
*/
public Player(String playerName, int evenOrOdd){
this.playerName = playerName;
this.evenOrOdd = evenOrOdd;
}
/**
* プレイヤーの勝ち負け判定
*/
@Override
public void update(Observable master, Object arg) {
if(master instanceof Game){
int masterNum = ((Game) master).getDiceTotalValue();
if(masterNum % 2 == this.evenOrOdd){
System.out.println(this.playerName+"さんの勝ち!!");
}else{
System.out.println(this.playerName+"さんの負け!!");
}
}
}
}
package diceGame;
import java.util.Observable;
import java.util.Observer;
public class Charlatan implements Observer {
private String charlatan;
/**
* イカサマする人の名前を設定
* @param name
*/
public Charlatan(String name){
this.charlatan = name;
}
/**
* プレイヤーの勝ち負け判定
* @param master
* @param arg
*/
@Override
public void update(Observable master, Object arg) {
if(master instanceof Game){
int masterNum = ((Game) master).getDiceTotalValue();
// ここでイカサマする。
if(masterNum % 2 == masterNum % 2){
System.out.println(this.charlatan+"さんの勝ち!!");
}else{
System.out.println(this.charlatan+"さんの負け!!");
}
}
}
}
以下、実行結果
サイコロの目 :6
サイコロの目 :2
丁半揃いました。よござんすね?
丁乃助さんの勝ち!!
半次郎さんの負け!!
用事を思い出したので帰らせていただきやす。
お、やってる。やってる。
サイコロの目 :2
サイコロの目 :6
丁半揃いました。よござんすね?
イカ政さんの勝ち!!
丁乃助さんの勝ち!!
#解説とか反省とか
##解説の方
java.utilのObservableクラスとObserverクラスを使って実装しています。使わないで自力で実装もできるのですが、今回はこっちでやりました。使わない方は「Observerパターン」とかでググるといっぱい出ます。
・1回目のゲームの後に半次郎さんが抜けて代わりにイカ政さんが追加されています。こんな感じでデータの変更によって実行されるクラス(Observer)は増やしたり減らしたりできます。
・丁乃助さん・半次郎さんはちゃんとしたプレイヤーですが、イカ政さんはズルをしています(Charlatanクラスは勝ち負け判定で絶対に勝ちになる)。処理が異なるクラスも追加しておけば同じように処理ができます。
##反省の方
本当のゲームならゲームの度にプレイヤーも半か丁か選べたらいいんですけどね。途中で面倒になってこんな実装で終わらせてしまった。
名前で半か丁か(イカサマ師か)わかりやすくしたかったので一緒にしてしまいましたが、コンストラクタはプレイヤーの名前だけにして、半か丁かはsetterメソッド作ればよかったかなぁと。
参考書籍丸コピしない場合は「何を作るか?」から考えなきゃいけないので、これはこれで面白いかと思います(時間はかかるけど)。
次は「Decoratorパターン」です。