私がそれを説明したように、オープン/クローズされた原則は、一度書かれたコードは修正されるべきではないと述べています(バグ修正を除く)。しかし、ビジネスルールが変更された場合、それらの変更を実装するコードを変更すべきではありませんか?私はそれが私には意味をなさないので、私は原理がどのようにかについて何かを理解していないと思う。
私がそれを説明したように、オープン/クローズされた原則は、一度書かれたコードは修正されるべきではないと述べています(バグ修正を除く)。しかし、ビジネスルールが変更された場合、それらの変更を実装するコードを変更すべきではありませんか?私はそれが私には意味をなさないので、私は原理がどのようにかについて何かを理解していないと思う。
回答:
これはおそらく、説明するのに最も堅実な原則です。私が試してみましょう。完璧に機能し、バグのないInvoiceクラスを書いたと想像してください。請求書のPDFを作成します。
次に、誰かが、リンクを含むHTML請求書が欲しいと言います。この要求を満たすために請求書のコードを変更することはありません。代わりに、別のクラス、HTMLInvoiceを作成します。これは、現在必要なことを行います。HTMLInvoiceで多くの重複コードを記述する必要がないように、継承を利用します。
古い請求書を使用していた古いコードが破損したり、実際に影響を受けたりすることはありません。新しいコードはHTMLInvoiceを使用できます。(LのLiskov Substitutabilityも行うと、Invoiceインスタンスを想定している既存のコードにHTMLInvoiceインスタンスを与えることができます。)誰もが幸せに暮らしています。
請求書の変更は終了し、延長は可能です。また、これを機能させるには、事前に請求書を適切に作成する必要があります。
ObjectMentorのボブおじさんの仲間によるオープンクローズドプリンシパルの記事を読みましたか?私はそれがそこにあるより良い説明の一つだと思います。
オブジェクト指向設計には多くのヒューリスティックが関連付けられています。たとえば、「すべてのメンバー変数はプライベートにする必要があります」、「グローバル変数は使用しないでください」、「ランタイム型識別(RTTI)の使用は危険です」などです。これらのヒューリスティックのソースは何ですか?何が本当ですか?彼らはいつも本当ですか?このコラムでは、これらのヒューリスティックの根底にある設計原理、つまりオープンクローズド原理について調べます。
Ivar Jacobsonが述べたように、「すべてのシステムはライフサイクル中に変化します。最初のバージョンよりも長く続くと予想されるシステムを開発する場合、これを念頭に置いておく必要があります。」バートランドマイヤーは、1988年に有名なオープンクローズドプリンシパルを考案したずっと前に、私たちに指導をしてくれました。彼を言い換えると:
ソフトウェアエンティティ(クラス、モジュール、機能など)は、拡張のために開かれている必要がありますが、変更のために閉じられている必要があります。
プログラムへの単一の変更が従属モジュールへのカスケードの変更をもたらす場合、そのプログラムは、「悪い」デザインに関連するようになった望ましくない属性を示します。プログラムは壊れやすく、硬直し、予測不能で再利用不能になります。オープンクローズド原則は、これを非常に簡単な方法で攻撃します。それは、決して変わらないモジュールを設計するべきだと言っています。要件が変更された場合、すでに動作している古いコードを変更するのではなく、新しいコードを追加することにより、そのようなモジュールの動作を拡張します。
説明
開閉原理に準拠するモジュールには、2つの主要な属性があります。
- それらは「Open For Extension」です。
これは、モジュールの動作を拡張できることを意味します。アプリケーションの要件の変更に応じて、または新しいアプリケーションのニーズを満たすために、モジュールを新しい異なる方法で動作させることができること。- それらは「変更のためクローズ」です。
このようなモジュールのソースコードは侵害されています。誰もソースコードを変更することはできません。これらの2つの属性は互いに対立しているように見えます。モジュールの動作を拡張する通常の方法は、そのモジュールに変更を加えることです。変更できないモジュールは通常、動作が固定されていると考えられています。これら2つの対立する属性はどのように解決できますか?
抽象化が鍵です...
ケイト・グレゴリーによって答えは非常に良いですが、新しい要件は、既存の比較的小さな変化で満足させることができる別の状況を検討しInvoice
たクラスを。たとえば、請求書PDFに新しいフィールドを追加する必要があるとしましょう。OCPによると、コードの数行を変更することで既存の実装に新しいフィールドを追加できる場合でも、新しいサブクラスを作成する必要があります。
私の理解では、OCPは80年代および90年代初期の現実を反映しており、プロジェクトではバージョン管理さえ使用されず、自動回帰テストや洗練されたリファクタリングツールの利点はほとんどありませんでした。OCPは、手作業でテストして本番環境に入れていたコードを壊すリスクを回避する試みでした。現在、動作中のソフトウェア(バージョン管理システム、TDDおよび自動テスト、リファクタリングツール)が破損するリスクを管理するためのより良い方法があります。
個人的には、この原則はひとつまみの塩で取られるべきだと思います。コードは有機的であり、ビジネスは変化し、時間の経過とともにビジネスのニーズに応じてコードが変化します。
抽象化が重要であるという事実に頭を悩ませるのは非常に難しいと思います。抽象化が元々間違っていた場合はどうなりますか?ビジネス機能が大幅に変化した場合はどうなりますか?
この原則は、基本的に、設計のオリジナルの意図と動作が決して変わらないことを保証します。これはおそらく、パブリックAPIを使用し、クライアントが新しいリリースや他のいくつかのケースに追いつくのに苦労している人に有効です。ただし、会社がすべてのコードを所有している場合は、この原則に挑戦します。
コードのテストカバレッジを十分に確保すると、コードベースのリファクタリングが簡単になります。つまり、物事を間違えても大丈夫です-テストは、より良い設計に導くのに役立ちます。
テストがない場合、この原則は妥当です。