#お詫びと訂正(2016/06/26)
Strategyパターンの説明について誤った内容を記述していたのでお詫びと内容の修正します。
なるべく早めに修正したかったのですが、そういう時に限って用事が入ったりなんやかんやで時間が経ってしまいました。今後も誤った内容を投稿してしまうことがあると思いますが、その際は気付いた方に指摘していただけると助かります。
今後ともよろしくお願いいたします。
#参考書籍
Head Firstデザインパターン――頭とからだで覚えるデザインパターンの基本
デザインパターンって何?
ベテランの人達が「こういう時はこういう実装にした方がいいと思うよ。」ってのをまとめたやつ。
Strategyパターンってどんなの?
参考書籍ではカモのシミュレーションゲームを例にしていましたが、参考書籍に書いてあるものをそのまま写経してもつまらないのでRPGゲームのキャラクター作成っぽいので実装してみました。
設定:キャラクターは名前・職業・特技を選べる。他はキャラクター共通の行動。具体的には下記の通り。
- 名前:自由に決められる。
- 職業:複数の中から選べる(サンプルでは魔法使いのみ)。
- 特技:複数の中から選べる(職業とは無関係に選べる)。
- 防御:全キャラクター共通。
- 逃げる:全キャラクター共通。
上記のようにベースになる部分は共通、ちょっとずつ違うところがある機能を作る時に使えるパターン。
実装してみる。
ファイル数は多くなるけど一つ一つは難しいことはしていないです。
package rpgGame;
public class CreateCharacter {
public static void main(String[] args) {
// 意地でも魔法を使い続ける人
Character c1 = new Magician("ああああ");
c1.job();
c1.setAttackEachCharacter(new MagicalAttack());
c1.attack();
c1.defend();
c1.escape();
// 魔法使いのくせに剣持って戦う人
Character c2 = new Magician("いいいい");
c2.job();
c2.setAttackEachCharacter(new SwordAttack());
c2.attack();
c2.defend();
c2.escape();
}
}
package rpgGame;
/**
* 魔法使いクラス
*/
public class Magician extends Character{
/**
* コンストラクタ(キャラクター名の設定)
* @param name
*/
public Magician(String name) {
super(name);
}
/**
* 職業(魔法使いはMagicianクラスで固定)
*/
public void job(){
System.out.println("職業 :魔法使い");
}
/**
* キャラクター毎の攻撃を設定
* @param aec
*/
public void setAttackEachCharacter (AttackEachCharacter aec){
attackEachCharacter = aec;
}
}
package rpgGame;
public abstract class Character {
/**
* キャラクター毎の特技
*/
public AttackEachCharacter attackEachCharacter;
/**
* キャラクター名の設定
* @param name
*/
public Character(String name){
System.out.println("-----キャラクターを作成します-----");
System.out.println("名前 :"+name);
}
/**
* 職業の設定
*/
public abstract void job();
/**
* 特技の設定
* @param aec
*/
public void setAttackEachCharacter(AttackEachCharacter aec){
attackEachCharacter = aec;
}
/**
* 特技の表示
*/
public void attack(){
attackEachCharacter.attack();
}
/**
* 防御(共通)
*/
public void defend(){
System.out.println("防御する");
}
/**
* 逃げる(共通)
*/
public void escape(){
System.out.println("逃げる");
}
}
package rpgGame;
/**
* キャラクター毎の特技のインターフェース
*/
public interface AttackEachCharacter {
public void attack();
}
package rpgGame;
/**
* 特技の実装クラス(魔法)
*/
public class MagicalAttack implements AttackEachCharacter {
@Override
public void attack() {
System.out.println("魔法で攻撃します");
}
}
package rpgGame;
/**
* 特技の実装クラス(剣で攻撃)
*/
public class SwordAttack implements AttackEachCharacter {
@Override
public void attack() {
System.out.println("剣で攻撃します");
}
}
上記を実行すると下記のようになります。
-----キャラクターを作成します-----
名前 :ああああ
職業 :魔法使い
魔法で攻撃します
防御する
逃げる
-----キャラクターを作成します-----
名前 :いいいい
職業 :魔法使い
剣で攻撃します
防御する
逃げる
こんな感じで
- (防御・逃げる)→そのまま継承する
- (名前)→継承して引数を取る
- (特技)→継承してインターフェースを使って実装
となり、上記の中のうち3が__Strategyパターン__での実装となります。
例えば職業に兵士を増やしたい場合はMagicianクラスと同じような内容でSoldier.javaを実装すればOKです。