SOLID原則のオープン・クローズドの原則(OCP)についてRubyで解説
プログラミング #ruby #SOLID #オブジェクト指向 #クリーンコードオブジェクト指向プログラミングにおいて、コードの保守性、可読性、再利用性を高めるために、SOLID原則と呼ばれる5つの重要な設計原則があります。
今回は、このSOLID原則のうち、オープン・クローズドの原則 (Open-Closed Principle, OCP)についてRubyのサンプルコードを用いて解説していきます。
目次 / Index
SOLIDとは
SOLIDとは、5つの原則の頭文字を取った略語です。
- Single Responsibility Principle(SRP): 単一責任原則
- Open Closed Principle(OCP): オープン・クローズドの原則
- Liskov Substitution Principle(LSP): リスコフの置換原則
- Interface Separation Principle(ISP): インターフェース分離の原則
- Dependency Inversion Principle(DIP): 依存性逆転の原則
オープン・クローズドの原則 (Open-Closed Principle, OCP)とは
オープン・クローズドの原則は、ソフトウェアの構成要素(クラス、モジュール、関数など)は拡張に対してオープンであり、修正に対してクローズドであるべきだという原則です。
つまり、既存のコードを変更することなく、新しい機能を追加できるように設計します。これは、インターフェースや抽象クラスを利用することで実現できます。
この原則により、クラスに変更を加える際、既存のコードを書き換えてバグが発生してしまうことを防ぐことが出来ます。
以降、実際のコードで解説します。
オープン・クローズドの原則に違反しているコード
以下のPost
クラスを例にします。
class Post
def initialize(args)
@title = args[:title]
@content = args[:content]
@format = args[:format]
end
def render
case @format
when :markdown
render_markdown
when :html
render_html
end
end
private
def render_markdown
# ...
end
def render_html
# ...
end
end
こちら、見ての通り、render
メソッドが@format
によって呼び出すメソッドを変えています。
もし、これに新しく@format
が:csv
の場合の処理を追加しようとするとどうでしょうか?
render
メソッドを変更しないといけませんが、このrender
メソッドは@format
によって各メソッドを呼び出す責務を持っており、もしここに変更を加えるなら既存の条件が正しく動いていることを確認しなければいけません。
この確認作業は変更の回数と比例して増加していき、開発スピードは徐々に低下していくことが予想されます。
この状態をオープン・クローズドの原則(OCP)に則った形に修正します。
オープン・クローズドの原則に則ったコード
以下が修正したコードとなります。
class Post
def initialize(args)
@title = args[:title]
@content = args[:content]
@renderer = args[:renderer]
end
def render
@renderer.render(self)
end
end
class Renderer
def render(post)
raise NotImplementedError, "Subclasses must implement render method"
end
end
class MarkdownRenderer < Renderer
def render(post)
# ...
end
end
class HtmlRenderer < Renderer
def render(post)
# ...
end
end
こちら見ての通り、Post
クラスに@format
を渡さずrenderer
を渡しています。
そして、render
メソッドはrenderer
のメソッドをコールしており、特に処理を行っておりません。
これにより、もし新しくcsvとしてレンダリングしたいというニーズがあってもRenderer
クラスの子クラスとしてCsvRenderer
を作成し、こちらをPost
クラスに渡せば良いだけとなり、Post
クラスは特に変更が必要ありません。
こうしてオープン・クローズドの原則に則った状態となったと言えます。
今回の例の重要な部分はPost
クラスはあくまでもrender
メソッドを必ず持つというRenderer
という抽象クラスに依存しているという点です。
この部分は、基本インターフェースでの実装となると思いますが、Rubyは言語的にインターフェースがないため、疑似抽象クラスによるダックタイピングでの実装となっております。
最後に
プログラミングに慣れている人からすると、インターフェースの基本的な使い方じゃんとなると思いますが、初学者などは馴染みがなかったりするかもしれませんので、このように原則として認知されていることは役立つなあと記事を書いていて思いました。
次回はリスコフの置換原則(LSP)について記事を書こうと思います。