Clean Architecture 達人に学ぶソフトウェアの構造と設計を読んで、オブジェクト指向の原則について学びがあったので、Rubyのコード例と共に内容を整理してみました。
Clean Architecture 達人に学ぶソフトウェアの構造と設計
- 作者: Robert C.Martin,角征典,高木正弘
- 出版社/メーカー: KADOKAWA
- 発売日: 2018/07/27
- メディア: 単行本
- この商品を含むブログを見る
※私の学びのメモなので理解が間違ってる可能性があります、間違ってたらすいません🙇♂️
開放閉鎖の原則(Open–closed principle)とは?
ソフトウェアのエンティティは(中略)拡張に対して開かれていなければならないが、変更に対しては閉じていなければならない。 https://ja.wikipedia.org/wiki/SOLID
この原則は、既存の振る舞いを変更することなく機能の拡張を行えるように設計するという原則ですね。
単一責任の原則の例とコード
開放閉鎖の原則を意識できていないコードと例
例えば下記のようなファイルパスとファイル形式を受け取って、パースした何らかのオブジェクトを返すようなClassがあったとします。
Parser.call('./records.csv', :csv) Parser.call('./records.json', :csv) class Parser def self.call(file_path, type) case type when :csv then parse_from_csv when :json then parse_from_json end end def parse_from_csv # return parsed object. end def parse_from_json # return parsed object. end end
このClassに「変換対象としてXML形式を追加する」といった対応が発生した場合はどうでしょうか? 引数でファイル形式に依存した実装が含まれているため、ファイル形式が追加されるたびに実装の修正が必要そうですね・・・!
開放閉鎖の原則を意識してリファクタリングしてみる
以下のようにレコードの項目のhashを引数にParser.call
を呼び出すような実装にするとどうでしょうか?
csv_hashes = CSV.read('./records.csv').map(&:to_h) json_hashes = JSON.parse(File.read './records.csv').map(&:to_h) Parser.call(csv_hashes) Parser.call(json_hashes) class Parser def call(hashes) # rturn parsed objects. end end
Hashのオブジェクトを使って抽象化して渡すというルールを守ることでParser
クラスはどんなファイル形式でも変更が必要なくなりましたね。
また、オブジェクトを作るという部分に関して関心を持っていないので、オブジェクトの作成方法が変わってもParser
のコードを修正する必要はありません。
このように直接ではなく抽象化した共通なものを使うことによって実装を変更することなく拡張することが出来ますね🙌
おわりに
今回はオブジェクト指向のSLID原則「開放閉鎖の原則(Open–closed principle)」について自分の理解をRubyのコード例とともに説明してみました。
開放閉鎖の原則を意識してコードを書くと、ソフトウェアの拡張性を担保して汎用性の高いコードを書くことができそうですね!
次回は「リスコフの置換原則(Liskov substitution principle)」について書いてみようかと思います 🙇♂️
参考
Clean Architecture 達人に学ぶソフトウェアの構造と設計
- 作者: Robert C.Martin,角征典,高木正弘
- 出版社/メーカー: KADOKAWA
- 発売日: 2018/07/27
- メディア: 単行本
- この商品を含むブログを見る