読み込み中...

SOLID原則のオープン・クローズドの原則(OCP)についてRubyで解説

プログラミング #ruby #SOLID #オブジェクト指向 #クリーンコード
2024年5月10日
2024年6月6日
SOLID原則のオープン・クローズドの原則(OCP)についてRubyで解説

オブジェクト指向プログラミングにおいて、コードの保守性、可読性、再利用性を高めるために、SOLID原則と呼ばれる5つの重要な設計原則があります。

今回は、このSOLID原則のうち、オープン・クローズドの原則 (Open-Closed Principle, OCP)についてRubyのサンプルコードを用いて解説していきます。

SOLIDとは

SOLIDとは、5つの原則の頭文字を取った略語です。

  1. Single Responsibility Principle(SRP): 単一責任原則
  2. Open Closed Principle(OCP): オープン・クローズドの原則
  3. Liskov Substitution Principle(LSP): リスコフの置換原則
  4. Interface Separation Principle(ISP): インターフェース分離の原則
  5. 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)について記事を書こうと思います。



システム開発やDX戦略などでお困りの際はお気軽にご相談ください。

※通常1営業日以内に回答致します。

お問い合わせはこちら
Top