私はまだ仕事をしておらず、SOLIDの原理を勉強して、最近扱っています。オープンクローズの原理についてはかなり読みましたが、残念ながらほとんどの本と記事は同じ例を共有しています。次のことを理解してください。クラスが変更された後にクラスを変更してはならない場合
ただし、基本クラスの実装を変更する必要がある場合の問題(たとえば、基本クラスレベルで実装されているメソッド)には対処していません。なぜこの原則はそれを扱わないのですか?
拡張機能に対して開いたままにしておくことのポイントは、その直接変更を行う必要がないようにすることです。
直接変更することは常に可能ですが、かなりのコストがかかる可能性があります。 OCPは、要件の変更に伴う直接変更の必要性を避け、コストがかかる設計から始めるように求めます。
問題のある動作の多態的な置換を可能にする設計は、変更したいコードに触れる必要がないことを意味します。新しいコードを書くだけです。
つまり、基本クラスの実装を変更する必要がある場合は、OCPの追跡に失敗しています。その実装を別の場所で記述された他のコードに置き換えることができる設計を使用する必要がありました。
これを行うには多くの方法があります。ポリモーフィズムにはさまざまな形があります。継承、構成、委任、ラッパー、それは何度も続きます。これらのいずれでも、基本コードの実装が呼び出されるのを回避できます。
この実装に直接アクセスするコードを記述して、他の実装に置き換える方法をだれにも与えられない場合は、変更前にOCPに違反しています。実装を変更する必要がないことが確実であるか、実装に直接変更を加えるコストを負担する意思がある場合を除いて、これを行わないでください。
原則が基本クラスの実装を直接変更する必要性に対応していないということではありません。それはそれをする必要性を生み出すことを避けるようにあなたに明示的に伝えます。
現実の世界では、要件の変更は物事の変更を意味することがありますが、それが発生する頻度を軽減する方法があります。 SOLIDは、現在の状況にとって最も重要なものを決定するために、開発者次第で互いに競合する場合がある原理のリストです。
アルゴリズムを変更する場合の一般的な解決策は、実行時にオブジェクトを作成するときにアルゴリズムを提供するように戦略パターンを使用することです。そのため、さまざまなオブジェクトを使用できます。これは、依存関係の逆転の原理の一部でもあります。例として勾配の計算を使用してみましょう。勾配を曲線化する方法としない方法は複数ある可能性があるため、勾配を計算するクラスには、作成の一部としてその曲線を提供する関数が必要です。つまり、同じクラスで、そのクラスを変更せずに異なる方法で成績を計算させることができます。
クラスを閉じたままにしておくためのもう1つの方法は、単一の責任の原則を使用することです。これは、クラスをいつ変更する必要があるかを決定するのにも役立ちます。クラスの責任に変更がある場合、それを変更する必要がある可能性が非常に高くなります。クラスに複数の責任がある場合、一度に複数の責任を変更するため、変更が必要になる可能性が高く、バグを引き起こす可能性が高くなります。評点を計算するために、スコアを計算するプロセスのみを考慮し、そのスコアを文字、パーセンテージ、合格/不合格などの形式にフォーマットするクラスで拡張する基本クラスを持つことができます。
理想的には、クラスが変更される唯一の理由は、クラスの責任の変更に直接関連する要件です。ドメインによっては、これは一定または非常にまれな場合があります。
クラスは変更に対してのみクローズされることになっています。ただし、拡張機能は利用できます。
したがって、クラスにAddOne
メソッドがあり、値に1を追加する場合、AddOne
を変更して、値に2を追加する必要があります。それは変更であり、クラスはそれに閉じています。
代わりに、その新しいアルゴリズムを処理する新しいメソッドAddTwo
が追加されます。それは拡張機能であり、クラスはそれを受け入れます。
ルールの例外は、AddOne
にバグが見つかった場合です。その後、その動作を変更できます。