オブジェクト指向による開発の設計指針の一つに「開放閉鎖原則」というものがあると聞きました。
これは変更の理由ごとにクラスを分割することで、新たな仕様追加には新たなクラスを増やすことで対応するというものだと解釈しました。
しかし、一つの要素が追加されるごとに多くの異なる実装が必要な場合はどうやって適用すべきなのでしょうか。
例えばゲームを設計してるとして、キャラクターが1つ増やすとします。
このゲームは、キャラクターごとにいくつもの階層に渡る機能を別に実装する必要があるとします。
こういった場合に、開放閉鎖原則を守りながらクラス設計をするにはどうしたらよいでしょうか?
※追記1
至らぬ点が多々あり、申し訳ございません。
「これは変更の理由ごとにクラスを分割することで、新たな仕様追加には新たなクラスを増やすことで対応するというものだと解釈しました。」
これは解釈以前に内容が伝わる文章になっていませんでした。
変更の理由=新たな仕様追加時には新たなクラスを追加するような設計にするという意味です。
想定しているケースの簡単な例を記載します。拙いコードで申し訳ありませんが、ご確認下さい。
前提条件
・キャラクターを採集して点数を競うイベントがある
・点数の計算式はキャラクターごとに異なる
・点数の計算式は時間帯や曜日によっても異なる
C#
1 class Monster 2 { 3 //★モンスターごとに初期化が必要なフィールド 4 //攻撃、防御など複数の戦闘用パラメーター 5 //習得中の技 6 //場所ごとの遭遇率 7 //etc... 8 9 10 //時間帯と曜日により点数を返すメソッド 11 public int GetScore(TimeZone timeZone,Week week) 12 { 13 //省略 14 } 15 16 17 //危惧している点:分岐ごとの処理メソッドが沢山増える 18 private GetScoreByMoning() 19 { 20 //省略 21 } 22 23 private GetScoreByNone() 24 { 25 //省略 26 } 27 28 private GetScoreByNight() 29 { 30 //省略 31 } 32 33 } 34 35 class MonsterList : List<Monster> 36 { 37 //List内のMonsterの点数を合計する 38 public int GetTotalScore() 39 { 40 //省略 41 } 42 43 } 44 45 class Contest 46 { 47 //MonsterListのTotalScoreによりGiftを返す 48 public Gift GetGift(MonsterList monsters) 49 { 50 //省略 51 } 52 53 54 } 55 56 public enum Gift 57 { 58 //省略 59 } 60 61 public enum Week 62 { 63 //省略 64 } 65 66 public enum TimeZone 67 { 68 //省略 69 }
問題として考えている点は主に2つになります。
・キャラクター固有の特徴を表すフィールドの初期化が複雑で膨大になる
・条件分岐ごとのメソッドにより、メソッド数が膨大になる
回避策として、例えばMonsterAに対してMonsterAScoreクラスを作成して処理を委譲することを考えたのですが、そうするとキャラクターが増えるごとにいくつものクラスを作成しなければいけなくなります。
どのようにアプローチすればよいでしょうか。
※追記2
開発者が知っておくべきSOLIDの原則
ソフトウェア原則[1] - OCP(Open-Close Principle)
Laravelチップシリーズ 2:SOLIDの世界1
以上のリンク先から、変更の理由=キャラクターの追加と設計段階で予想されるなら、キャラクターをそれぞれ共通のインターフェースを持った別のクラスにすることで既存のクラスの修正を行わなくてよいのが開放閉鎖原則のメリットだと考えておりました。
リンク先の内容が全て或いは一部誤っているのか、記載の内容はあっていて私の理解だけが誤っているのか自分には判断できません。
申し訳ありませんが、こちらのご指摘からお願いします。
「階層」とはオブジェクトの所持関係のことです。追記1で記述したコードの場合、キャラクタークラスのフィールドのオブジェクトが更に別のフィールドを持ち、その初期化の内容がキャラクターごとなら追記1の通り初期化が複雑で膨大になるのでは?と考えていました。
回答2件
あなたの回答
tips
プレビュー