開発者が沿うべき、Solid原則とは

Solid原則ってなに

オブジェクト指向プログラミングにおいて、開発者にとって読みやすく、メンテナンスが可能なプログラムを作成しやすくするために考えたルール

Solidの意味
S:SRP、単一責任の原則
O:OCP、解放閉鎖の原則
L:LSP、リスコフの置換原則
I:ISP、インタフェース分離の原則
D:DIP、依存性逆転の原則

今回は「SRP、単一責任の原則」と「OCP、解放閉鎖の原則」について解説したい。

単一責任の原則とは

調べてみると以下のように説明されている
・1つのクラスは1つだけの責任を持たなければならない。
・ソフトウェアの仕様の一部分を変更したときには、それにより影響を受ける仕様は
 そのクラスの仕様でなければならない
・クラスを変更する理由は1つ以上存在してはならない
つまり、かみ砕くと
・一つのプログラム(クラス)には一つの機能のことだけやらせよう

十得ナイフは便利だけど、プログラムの世界において十得ナイフは必要なし。
もし現実世界においても四次元ポケットが存在したら十得ナイフはいらない。
栓抜きを必要とした時、四次元ポケットからわざわざ十得ナイフを取り出して十得ナイフの栓抜きを使うようなことはせず、専用の栓抜きを取り出せばいい

▼実際のソースコード NGパターン

デジプラ②

 

出力結果
→PC:100000 yen

ここで「商品の税込み価格を計算可能にする」という案件と、「表示を変更して」という案件が発生したら、どちらの案件も RegistShowCommodityクラスの修正となってしまう

以下の3クラスに分割
商品の登録を行う RegistCommodityクラス
商品の価格計算を行う CalcCommodityクラス
価格表示を行う ShowCommodityクラス

具体的なコード

デジプラ②

出力結果
■CommodityName :PC
■CommodityPrice:110000 yen

単一責任の原則まとめ

1つのクラスに複数のプログラマーが修正を加えてファイルがコンフリクトする、といったことがクラスをわけることで無くすことができる
変更するクラスが明確になったことで修正後の影響範囲がわかりやすい

ゲーム開発ではキャラクターの移動や重力などもそれぞれ別のクラスとなっており、
そのクラスをキャラクターに付与する、といった設計が多かった

解放閉鎖の原則とは

調べてみると以下のように説明されている
・拡張に対して開いていなければならず、
・修正に対して閉じていなければならない
つまり、かみ砕くと
・何か機能追加があった場合には、既存のコードには
 手を入れず、オブジェクトの追加によって対応できるようにすること
・バグ修正が入った場合には、バグが入ったオブジェクトだけを修正することで
 対応終わるように擦ること

▼実際のソースコード NGパターン
この マリオ に対し新たな種類の status(メタルマリオとか) を追加する場合、attack メソッドや miss メソッドに変更を加える必要がでてくる

デジプラ③

▼具体的な対応方法
インターフェースを使って解決する
・マリオインターフェース

デジプラ④

・マリオそのもののクラス

デジプラ⑤

・マリオの状態を管理するクラス

デジプラ6

解放閉鎖の原則のまとめ

attackメソッド と missメソッド に対し変更を加えることなく機能を拡張できるようになった。
一方で、 jump の振る舞いを変更しなければならなくなった場合(羽のついた マリオ など)には、既存のソースコードに変更を加える必要があります。この場合、やはりOCP違反となる。

あらゆるケースを想定して完璧に閉じることは現実的ではないし、jumpのふるまいが変わらなかったら、かえってソースコードが不必要な複雑になるだけ

あらゆる要求に対応しようとするのではなく、予測不可能な部分については実際に変更が発生してからOCPを適用するという方針が現実的

Solid原作のSとOのまとめ

変化の兆候がないのにSRPを含めた原則を適用するのは賢明ではない。
原則を適用することを目的にするのはナンセンス。
結合している役割を見つけそれらを分離する作業は、ソフトウェア設計の本質である。