Hama Blog

Hama Blog

主にtech関連の記録

開放/閉鎖原則(OCP)について学習してみた

概要

単一責任原則(SRP)について考えてみた - Hama Blog の記事に引き続き、SOLID原則のうちの、開放/閉鎖原則(open/closed principle、OCP)について、自分なりに調べて学んだことをまとめてみた。

※ この記事ではサンプルコードを使うなどしておらず、あまり具体的な解決方法については触れていません🙏

最初に結論

  • 抽象部分は変更されないように閉鎖するが、その具象部分は拡張できるように開放するということ。

    • つまり、抽象部分を抽象クラスやインターフェースとして定義することで、変更から保護し、それを継承、実装する具象クラスやメソッドを通じて機能を拡張できるようにすること。
    • Strategyパターン、Template Methodパターンが典型的な使い方。

  • OCPの適用は起こる可能性の高い変更に限定すべき。 1

    • 抽象化の設計には時間がかかるし、そもそもどんな変更が起こるかわからないこともあるため、そのコストに見合わないかたちで無闇に時間をかけるわけにはいかないため。

  • 色々な意味で、オブジェクト指向設計の核心らしい。 2

    • OCPに従うことで、オブジェクト指向技術から得られる最大の利益(柔軟性、再利用性、保守性)を享受できる。

そもそも開放/閉鎖原則(OCP)とは

Wikipediaの説明を拝借すると以下。

開放/閉鎖原則 - Wikipedia

開放/閉鎖原則(かいほうへいさげんそく、open/closed principle、OCP)とは、オブジェクト指向プログラミングの設計への提言である。

ソフトウェア要素(クラス、モジュール、関数など)は、拡張に対しては開いており、修正に対しては閉じているべきである。 software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification.[1]

この原則に従っていれば、ソースコードの修正をせずとも、各要素の振る舞いを拡張することが可能になるとしている。

また、どうやら「メイヤーの開放/閉鎖原則(1988年)」と「マーチンの開放/閉鎖原則(1996年)」の2通りがあるらしい。

前者はクラスの継承を基本とし、後者はメソッドの継承を基本としている、という違いがあるようだった。

もう少し詳しく調べてみる

Wikipediaの説明だけだとよくわからなかったので、ロバート・C・マーチンさんが書かれた『Agile Software Development』の邦訳書であるアジャイルソフトウェア開発の奥義 第2版 オブジェクト指向開発の神髄と匠の技という本を買ってみた。

そのなかに、「第9章 オープン・クローズドの原則(OCP)」という章があったので、いくつか抜粋してみる。

OCPに従って設計されたモジュールは以下の特徴的な属性があるとのこと。

  1. 拡張に対して開かれている(オープン:Open)

    ...(中略)...

    アプリケーションの仕様要求が変更されても、モジュールに新たな振る舞いを追加することでその変更に対処できる。

    ...(中略)...

  2. 修正に対して閉じている(クローズド:Closed)

    モジュールの振る舞いを拡張しても、そのモジュールのソースコードやバイナリコードはまったく影響を受けない。

    ...(中略)...

本にも書かれているが、矛盾している。。

ではどうすればモジュールに手を加えずに、モジュールの処理内容を変えられるかというと、「抽象」が鍵とのこと。

「抽象」を使えば、コードを修正しなくても、その「抽象」の派生クラスを新たに追加するだけでモジュールの振る舞いを拡張できる

なので、Closedにすべき部分は抽象化(抽象クラスやインターフェースで実装)し、それを具体的な振る舞いに具象化(具象クラス、具象メソッドで実装)することに対してOpenにしようとするもの、ということだと思われる。

StrategyパターンとTemplate Methodパターンが例として軽く紹介されていて、この2つはOCPに準ずるために利用される最も典型的なパターンらしい。

たしかに、そういうことなら上記の一見矛盾したように思える特徴が理解できる。

(ちなみに、本のなかでは「抽象クラス」と「抽象インターフェース」という用語が混ざって出てくるので、ちょっとややこしかった)

また、OCPの適用については、以下のような注意もされていた。

OCPに準ずるという行為が高くつきすぎる場合もある。開発には時間がかかるし、適切な抽象を行うのにも努力が必要だ。それに、こういった抽象がソフトウェア設計をさらに複雑にしてしまう可能性もある。また、開発者が一度に扱うことができる抽象の量には限界があるので、OCPの適用は起こる可能性の高い変更に限定すべきなのは明らかだ。

「起こる可能性の高い変更に限定すべき」というのは、OCPというか、特にビジネスにおけるアプリケーション設計の本質なのかなあと思った。

あと、たしかに原則には従っているんだろうけど、逆に複雑になっている実装はたまにある気がするので、そこらへんの見極めも本当に難しいと思う。

さいごに、OCPの紹介の結論として以下のことが書かれていた。

色々な意味で、オープン・クローズドの原則(OCP)はオブジェクト指向設計の核心である。この原則に従うことで、オブジェクト指向技術から得られる最大の利益(柔軟性、再利用性、保守性)を享受できる。しかし、オブジェクト指向プログラミング言語を使えば自動的にOCPに準拠できるわけではない。また、アプリケーションのあらゆる部分で抽象を無闇に使えばいいわけでもない。むしろ、開発者が担当する部分で最も頻繁に変更されるプログラム部分にだけ的を絞って抽象を適用するように努めるべきである。早まった「抽象」をしないことも、「抽象」を使うのと同等に重要なことなのだ。

たしかに、OCPの適用ができれば、特に再利用性が高くなる気がした。
(関係ないが、オブジェクト指向は一概には説明できないところがあると思っていたけど、「最大の利益(柔軟性、再利用性、保守性)」について述べれたらそれっぽくなりそう)

また、一つ前の引用とも被るけど、抽象化すべきタイミングの勘所についても鍛えていきたいなあと思った。

どれもそうだけど、いかに多くの経験が積めるかが大事そう。

今回も、いろいろ勉強になった。


  1. アジャイルソフトウェア開発の奥義 第2版 オブジェクト指向開発の神髄と匠の技 の「第9章 オープン・クローズドの原則(OCP)」の『9.4.4 「先を見越した構造」と「自然な構造」』より
  2. アジャイルソフトウェア開発の奥義 第2版 オブジェクト指向開発の神髄と匠の技 の「第9章 オープン・クローズドの原則(OCP)」の『9.5 結論』より