🍉
Rubyでさらっと学ぶSOLID原則②「オープン・クローズドの原則」
SOLID原則とは
ソフトウェアの拡張性や保守性を高めるための下記5つの原則のこと。
- S(Single-responsibility principle): 単一責任の原則
- O(Open-closed principle): オープン・クローズドの原則
- L(Liskov substitution principle): リスコフの置換原則
- I(Interface segregation principle): インターフェース分離の原則
- D(Dependency inversion principle): 依存性逆転の原則
オープン・クローズドの原則(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