よくわかるSOLID原則2: O(オープン・クローズドの原則)
ソフトウェアエンジニアが知っているべきSOLID原則についての記事です。SOLID原則は、5つの原則の頭文字を並べた言葉で、S・O・L・I・Dそれぞれの原則について、5回に分けて説明します。
1) Single Responsibility Principle:単一責任の原則
2) Open/closed principle:オープン/クロースドの原則
3) Liskov substitution principle:リスコフの置換原則
4) Interface segregation principle:インターフェース分離の原則
5) Dependency inversion principle:依存性逆転の原則
今回は2番目のオープンクローズドの原則です。
なぜソフトウェアエンジニアがSOLID原則について知っていなければいけないかは前回の記事をご覧ください。
オープンとクローズド
正直この文字列だけ見ても何を指してるかはわかりにくいと思います。何に対してオープンで、何に対してクローズドなのかの情報が抜け落ちているためです。
オープンにするのは、拡張に対してです。
クローズドにするのは、修正に対してです。
紹介する順番の都合で、まず修正に対してクローズドにすることについて触れます。
修正に対してクローズドであるべき理由
さて、なぜ修正に対してクローズドであるべきなのかについて、そもそも修正とは何かを考えるところから始めましょう。
修正とは、修正元のコードがあるからこその修正です。そして多くの場合、修正というのは既に動いているコードの事です。
既にあるコードを修正するというのはそれなりにコストのかかる行為です。
・ そのコードを修正することでどこに影響があるか調査しなければいけない
・ 修正の影響で、動作に支障が出ないか確認しなければいけない
SRPのときと同様です。
ただし、何かしらバグがあるのでそれを修正するのは仕方ありません。修正に対してクローズドにする、というのは別に修正してはいけないという意味ではありません。
ある関数・メソッド・クラスには、責任があります。それはドキュメントに書かれていたり、インターフェースとして定義されていたりする、自身は○○という機能を提供すると表明されているもののことです。
つまりクローズドの原則とは、機能追加の為に責任を修正すべきではない。ということです。
では、機能追加はどうすればいいのでしょうか?
拡張に対してオープンにすべき理由
拡張は修正とは異なります。何かしらのフックポイントを用意した上で、そのフックに新機能を追加するような仕組みです。
インターフェースを用いたやり方、イベント駆動やオブザーバーパターンを用いたやり方や、プラグイン機構などがあります。
あるいは委譲を用いて、あるクラスのさらに包み込むようなクラスを作成して、そのクラスは元のクラスよりも多くの機能を提供するようにするというようなやり方でしょうか。
このようにする理由は簡単です。
・ 既にあるものに悪影響を与えにくい
・ 新機能はガシガシ追加していきたいが拡張なら遠慮する必要はない
もちろん無計画な新機能の拡張は混乱を招く可能性があるので、SOLID原則の他の原則や、あるいはさらに別の人類の知恵を駆使して、あるべき設計をしなければいけません。
オープン・クローズドの原則
じつは、OCPはSRPよりも指針が少ないのです。経験則として、オープン&クローズドにするとうまくいくと分かっているものの、言語仕様やフレームワークその他の事情によっても、最適な設計は容易に変わりうるものです。
前回もサンプルコードを書きづらかったのですが、前回以上にサンプルコードを書きづらい原則です。
次の技術書典7で予定している、TypeScriptとクリーンアーキテクチャで、最高の開発者体験をしよう!の本では、TypeScriptのコードで踏み込んでいく予定です。
まとめ
機能追加を修正で行うのではなく、拡張で行うように心がけましょう。
次回は、SOLIDのLであるLiskov substitution principle:リスコフの置換原則について説明します。
この記事が気に入ったらサポートをしてみませんか?