こんにちは!河条です!
今回はC#でStrategyというプログラム設計について学びましょう!
今回はPHPじゃなくてC#だよ!こういう設計の知識はオブジェクト指向プログラムであれば他の言語でも使えるから知らない人はぜひ覚えてみてね🤗
※事前知識:C#の基本構文、オブジェクト指向の知識
今回やること
1、技をいくつか用意する
2、何体かのモンスターを生成する
3、モンスターは技を2つまで覚えられる
4、モンスターに1で作った技を使わせてみる
※ 今回はとりあえず機能の確認とStrategyがどんなものかを知るのが目的なので、モンスターの絵とかダメージ計算もなくDebug.Logに出力させるだけです
パッと思い浮かぶやり方
モンスターごとに技のメソッドを用意して、アルゴリズムをかく!となると思います!
ただしこのやり方は思いついただけでも2つ問題があります
1、異なるモンスターが同じ技を持っていても、それぞれモンスタークラスごとに同じ技のメソッドを書かなくてはいけない🤔
技の仕様変更あったらモンスターごとに書いていた同じ技のロジックを全部書き換えていくという作業が必要になり面倒ですね😇チーン
2、今覚えている2つの技をフラグか何かで管理する羽目になる🤔
技の数だけ条件分岐が必要という面倒くささになります。まあList使えば何とかできそうな気もするけど😇チンチーン
Strategyパターンとは
ではどうすれば良いか!ということでStrategyパターンです!
Strategyパターンはいろんな状況、仕様に応じてアルゴリズム(今回でいうモンスターの技)を簡単に変更することができます!
これを使って上記の2点の問題を解決しましょう!
ザックリとした考え方
実装方法としては、技クラスという抽象クラスを継承させた技固有のクラスを何個も作り、インスタンス化させたモンスターに2つ技を持たせるイメージです!
これでモンスターごとに同じ技を記述する必要は無くなりますし、技の仕様が変更になってもそれ1つだけ直せば大丈夫です!
また、モンスターには1番目 or 2番目の技を使え!という命令だけで条件分岐もなく持たせている技を使わせることができます!
実際のコード
まずはいきなりメイン処理を!割とスッキリしていると思います!
条件分岐も一切使わずに、また技の切り替えも簡単にできますね!
また新しい技が増えたとしてもモンスタークラスは触る必要なく、技クラスを増やしてインスタンス化するだけで対応できます!(依存関係のないプラグラムってやつですね!)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
public class StrategyStructure : MonoBehaviour{ private Monster _kawamon; void Start (){ //カワノバナというモンスター生成 _kawamon = new Monster("カワノバナ"); //カワノバナに技追加 _kawamon.Waza1 = new Hikkaku (); _kawamon.Waza2 = new KawanoCutter (); //カワノカッター攻撃 _kawamon.Attack(_kawamon.Waza2); //カワノバナの技1を毒爆弾に変更 _kawamon.Waza1 = new PoisonBom (); //毒爆弾攻撃 _kawamon.Attack(_kawamon.Waza1); //カワノカゲというモンスター生成 _kawamon = new Monster("カワノカゲ"); _kawamon.Waza1 = new Hinoko (); _kawamon.Waza2 = new Hikkaku (); //ひのこ攻撃 _kawamon.Attack(_kawamon.Waza1); } } |
上のコードの実行結果(技効果も載せてます)
ではメイン処理のようなプログラム組むための準備となる技クラスとモンスタークラスを作っていきましょう!
まずは冒頭でも書いた技の抽象クラスからです!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
/// <summary> /// 技の抽象クラス /// </summary> abstract class Waza{ /// <summary> /// 技の効果 /// </summary> public abstract void Skilleffect(); /// <summary> /// 技の威力 /// </summary> public int damage; /// <summary> /// 技の名前 /// </summary> public string waza_name; /// <summary> /// 技のタイプ 炎とか水とか雷とか /// </summary> public string waza_type; } |
次に技クラスを継承させて実際の技のクラスを書きましょう!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 |
/// <summary> /// 技名:ひっかく 技タイプ:ノーマル ダメージ:30 /// </summary> class Hikkaku : Waza{ public Hikkaku(){ this.damage = 30; this.waza_name = "ひっかく"; this.waza_type = "ノーマル"; } public override void Skilleffect(){ Debug.Log ("技効果なし!"); } } /// <summary> /// 技名:カワノカッター 技タイプ:草 ダメージ:60 /// </summary> class KawanoCutter : Waza { // Constructor public KawanoCutter(){ this.damage = 60; this.waza_name = "カワノカッター"; this.waza_type = "草"; } public override void Skilleffect(){ Debug.Log ("クリティカル率2倍"); } } /// <summary> /// 技名:毒爆弾 技タイプ:毒 ダメージ:90 /// </summary> class PoisonBom : Waza { // Constructor public PoisonBom(){ this.damage = 90; this.waza_name = "毒爆弾"; this.waza_type = "毒"; } public override void Skilleffect(){ Debug.Log ("相手を毒状態にする"); } } /// <summary> /// 技名:火の粉 技タイプ:炎 ダメージ:40 /// </summary> class Hinoko : Waza { // Constructor public Hinoko(){ this.damage = 40; this.waza_name = "火の粉"; this.waza_type = "炎"; } public override void Skilleffect(){ Debug.Log ("相手を火傷状態にする"); } } |
最後にモンスタークラスです!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
/// <summary> /// モンスタークラス モンスターの名前と技を初期化 /// </summary> class Monster { /// <summary> /// モンスターの技情報 覚える技は2つ /// </summary> private Waza _waza1; private Waza _waza2; /// <summary> /// モンスターの名前 /// </summary> private string name; // Constructor public Monster(string name){ this.name = name; } //Property public Waza Waza1 { get{ return this._waza1;} set{ this._waza1 = value; } } //Property public Waza Waza2 { get{ return this._waza2;} set{ this._waza2 = value; } } //モンスターの攻撃 public void Attack(Waza _waza){ Debug.Log( this.name + "の攻撃! " + _waza.damage + " ダメージ!"); //攻撃後の効果 _waza.Skilleffect (); } } |
ざっくりまとめ
モンスタークラスにprivateな技の変数を2つ用意し、メイン処理で代入しています!
攻撃時は代入した技に応じてAttack関数とSkilleffect関数が動いてくれます!
今回はカワノバナとカワノカゲのモンスター二匹だけだけど、三匹になっても四匹になっても同じようにモンスタークラスを生成して、技を代入すればいいです!
新しく技を増やしたかったら(水鉄砲とか)その都度、技クラスを作ればモンスタークラスはそのままで拡張できます!
依存関係のないプログラムの意味はこれで何となくわかると思います!
ただあくまでもStrategyの一番の特徴は簡単にアルゴリズムの切り替えができることです!
結構汎用性高いと思うのでぜひ使ってみてください!!!!(^o^)人(^o^)