SOLID原則とは?
1990年代後半〜2000年代にロバートCマーチンによって提唱されたモジュール間の接続の概念。SOLIDはオブジェクト指向においてバリエーションを扱う上で守った方が良い概念を集めた原則(「S:単一責任の原則」だけはこの限りじゃないですが。)になります。(バリエーションがないものを扱う場合は必ずこの原則に従う必要はありません。)
バリエーション
現実のプログラムには様々なバリエーションがある。バリエーションの変化によってそのバリエーション要素を使っているコードに様々な形で影響する。
- 明示的に扱っているもの
- 不完全なもの
- コードとしては扱ってないもの
それぞれのバリエーションがコードに引き起こす作用がどの程度のものなのかを都度考えることが重要。
例
「フォームの種類」(上位層)と「フォームの各行」(下位層)があった場合に「フォームの種類」の方が「フォームの各行」に比べて影響が大きいなど。
バリエーションがない例:SOLID原則の対象となりにくいもの
広く薄くテクノロジーを共通化する場合など。
- BaseController(WebでMVCのコントローラー層のベース。不正なリクエストをチェックするなど)
- BaseForm(画面の共通処理など)
- ViewModelBase(画面のモデルのbase)
- ValueObjectBase(値オブジェクトのbase)
ざっくりといえば
「O(オープンクローズドの原則)」と「依存関係逆転の原則」、「リスコフの置換原則」の実装コードはほぼ同じになります。(原則というだけあって視点が違うくらいという感じです。)
S(単一責任の原則)
「変更する理由」を意識する
変更する理由とは、「変更を要求する人間(利用する側)」のこと。単一の利用する人に対してのみ責務を負うコードを書くのが良いとされている。
「単一責任の原則」は「一つのクラスは一つの役割を持たせる」と勘違いされやすいが、「一つのクラスは単一の利用者や機能に対して責務を負う」ということが正しい理解になる。
例えば
利用者であれば、「ユーザー画面」と「管理者画面」があったとしてログインの処理を共通化して書いてしまうとそれぞれ別の修正なのに影響してしまう。なので、「ユーザー」と「管理者」でそれぞれ「ログイン処理」のコードを分けます。
機能であれば、「通知機能」があったとしてその下に「A機能」と「B機能」があった際にソースがごちゃごちゃしてしまう。
ただし同じような処理が出てくる。。
例えば、ログイン処理の中で「セッション判定」などのコードが出てきてほぼ同じようなコードになっている場合は、処理を抜き出して使う。(こうすることで、「単一責任」を守りながら「DRY」に記述することが可能)
O(オープン・クローズドの原則)
「新しいバリエーションのコードを作るときは既存コードに条件分岐を作るのではなく新しくクラスを追加するだけで対応しましょう。」という原則です。バリエーションはインターフェースを作ってそれを継承させて決まった形に作ります。
例
「上位層」のバリエーションが増えたらつられて「下位層」のコードも修正しなくてはいけないという状況を「オープンクローズドの原則」に違反しているとみなせる。
L(リスコフの置換原則)
別のバリエーションのクラスを置き換えてもエラーは出ないようにすること。使用するメソッド名は同じにする。
今後メソッドが増えた場合は?
ただ、今後Aの場合だけ必要なメソッド、Bの場合だけ必要なメソッドみたいな感じで増えていく可能性もあります。
そうした場合に委譲を使って影響範囲をさらに局所化します。
I(インターフェイス分離の原則)
「インターフェースを作るときは再利用できるようにできるだけ細かく区分けしてそれを組み合わせましょう」という原則。
クラスの利用者にとって余計なインターフェース(メソッドなど)があると、それだけ余計なリスクが発生し保守性を落とすことになる。
親を継承して子では必要なインターフェイスだけ提供させるようにする。
D(依存関係逆転の原則)
上位要素は下位要素に依存してはいけない。両方とも抽象に依存すべきであるという原則。
上位要素では実装は行わず抽象化すること。
例えば
Customerクラス(上位クラス)がPaymentクラス(下位クラス)をnewしていたらPaymentクラスの変更が、Customerクラスにモロに影響することになる。なので、具象クラスであるPaymentを使うよりも、抽象クラスを使うようにすると良いという原則。
この記事へのコメントはありません。