🍉

Rubyでさらっと学ぶSOLID原則②「オープン・クローズドの原則」

2021/10/03に公開

SOLID原則とは

ソフトウェアの拡張性や保守性を高めるための下記5つの原則のこと。

オープン・クローズドの原則(OCP)とは

「変更が発生した際に、なるべく既存のコードを修正せずにコードの追加だけで対応できるようにすべき」という考え方のこと。

他の記事でよくある定義では、上記を「拡張にオープンで、変更にはクローズドであるべき」と表現することが多いです。

オープン・クローズドの原則に違反している例

Slackに通知するためのクラスがあり、csvやmarkdownなど色々な形式で通知できるとします。

class SlackNotifier
  def notify(channel:, body:, format:)
    if format == 'csv'
      # csvで送信する
    elsif format == 'markdown'
      # markdown形式で送信する
    else
      # 平文で送信する
    end
  end
end

slack_notifier = SlackNotifier.new
# csvで通知したい場合
slack_notifier.notify(channel: 'test_channel', body: 'test_message', format: 'csv')

# markdownで通知したい場合
slack_notifier.notify(channel: 'test_channel', body: 'test_message', format: 'markdown')

上記の実装の問題点は、例えば「zip形式で送りたい」という要件が発生した場合に、既存のSlackNotifier#notifyメソッドを修正しなければいけない点です。

既存のメソッドを修正するということは、zip形式とは関係ないcsvやmarkdown形式での送信機能に悪影響を及ぼす可能性があります。

解決策

各送信形式ごとにクラスを分離するという解決策があります。

class SlackNotifier
  def notify(channel:, body:)
    raise NotImplementedError
  end
end

class SlackNotifierWithCsv < SlackNotifier
  def notify(channel:, body:)
    # csvで送信する
  end
end

class SlackNotifierWithMarkdown < SlackNotifier
  def notify(channel:, body:)
    # markdownで送信する
  end
end

class SlackNotifierWithPlainText < SlackNotifier
  def notify(channel:, body:)
    # 平文で送信する
  end
end

# csvで通知したい場合
slack_notifier_with_csv = SlackNotifierWithCsv.new
slack_notifier_with_csv.notify(channel: 'test_channel', body: 'test_message')

# markdownで通知したい場合
slack_notifier_with_markdown = SlackNotifierWithMarkdown.new
slack_notifier_with_markdown.notify(channel: 'test_channel', body: 'test_message')

このように実装しておけば、zip形式で送信したい要件が発生した場合に「SlackNotifierWithZip」というクラスを追加するだけで実現でき、既存のcsvやmarkdownで送信するクラスを修正する必要がなくなります。

オープン・クローズドの原則違反に気付くための質問

  • 新しく種類が増えるとき、既存コードを修正しないといけないか?
    • もし既存コードを修正しないといけない場合、オープン・クローズドの原則に違反している可能性がある。

参考文献

Discussion