16

この質問は、OCP とは何かに関するものではありません。また、単純な答えも求めていません。

だから、ここに私がこれを尋ねる理由があります。OCP は 80 年代後半に初めて説明されました。当時の考え方や文脈が反映されています。懸念事項は、ソース コードを変更して機能を追加または変更することは、コードが既にテストされて運用に投入された後で、リスクとコストがかかりすぎるということでした。そのため、既存のソース ファイルをできるだけ変更することを避け、サブクラス (拡張機能) の形でコードベースに追加するだけにするという考えがありました。

私が間違っているかもしれませんが、私の印象では、ネットワーク ベースのバージョン管理システム(VCS) は当時はあまり使用されていませんでした。ポイントは、VCS はソース コードの変更を管理するために不可欠であるということです。

リファクタリングのアイデアは、はるかに最近のものです。自動リファクタリング操作を可能にする洗練された IDE は、当時は確かに存在しませんでした。今日でも、多くの開発者は利用可能な最高のリファクタリング ツールを使用していません。ここでのポイントは、このような最新のツールを使用すると、開発者は文字どおり数千行のコードを安全に、数秒で変更できるということです。

最後に、今日、自動化された開発者テスト(ユニット/統合テスト) のアイデアが広まっています。それをサポートする多くの無料の洗練されたツールがあります。しかし、既存のコードをまったくまたはほとんど変更しない場合、大規模な自動テスト スイートを作成して維持することに何のメリットがあるでしょうか。OCP が要求する新しいコードは、新しいテストのみを必要とします。

では、今日の OCP は本当に理にかなっているのでしょうか? 私はそうは思わない。代わりに、新しい機能が新しいクラスを必要としない場合は、新しい機能を追加するときに既存のコードを変更することを実際に好みます。そうすることで、コードベースがよりシンプルで小さくなり、読みやすく理解しやすくなります。以前の機能が壊れるリスクは、VCS、リファクタリング ツール、および自動化されたテスト スイートによって管理されます。

4

6 に答える 6

9

OCP は、コードの消費者ではない場合に非常に役立ちます。私がクラスを作成していて、私または私のチームがそれを使用するすべてのクラスを作成している場合、私は同意します。物事の変化に伴うリファクタリングは、大したことではありません。

一方、顧客向けの API を作成している場合、または大規模な組織にさまざまな関心を持つ複数のコンシューマーがいる場合、簡単にリファクタリングできないため、OCP は重要です。

また、全員のニーズを満たすためにクラスをリファクタリングすると、結果として肥大化したクラスになります。コンシューマーがクラスを変更するのではなく拡張できるようにクラスを設計した場合、実際にはこの問題は発生しません。

于 2009-09-12T23:59:51.433 に答える
6

OCPがそうであるとは聞いたことがありません。多分あなたは何か他のものを参照しているかもしれませんが、私が知っているOCPは「モジュール/クラスは拡張のために開かれている必要がありますが、変更のために閉じられている必要があります。つまり、モジュールのソースコードを変更して拡張するべきではありませんが、モジュールまたはオブジェクトは簡単に拡張できる必要があります。

Eclipse (またはその他のプラグイン ベースのソフトウェア) について考えてみてください。ソース コードはありませんが、動作を拡張したり別の機能を追加したりするプラグインを誰でも作成できます。あなたは日食を修正しませんでしたが、あなたはそれを拡張しました。

そうです、オープン/クローズの原則は確かに非常に有効であり、非常に良い考えです。

アップデート:

ここでの主な競合は、まだ開発中のコードと、すでに出荷されて誰かによって使用されているコードとの間であることがわかります。そこで私は、この原則の著者であるバートランド・メイヤーに確認を取りに行きました。彼は言い​​ます:

モジュールが他のモジュールで使用できる場合、そのモジュールは閉じていると言われます。これは、モジュールが明確に定義された安定した記述(情報を隠すという意味でのインターフェース) を与えられていることを前提としています。実装レベルでは、モジュールのクロージャーは、モジュールをコンパイルし、おそらくライブラリに保存し、他のユーザー (そのクライアント) が使用できるようにすることも意味します

したがって、実際、オープン/クローズドの原則は、安定した、コンパイルおよび使用の準備ができているエンティティのみを指します。

于 2009-09-13T01:38:46.383 に答える
3

さて、これが私の応答です。

この原理の歴史的な起源については証明できませんが、現代でも頻繁に唱えられています。機能しているコードを変更することが危険だとは思いません (もちろんそうですが) アイデアを分離できるようにすることです。

コンポーネントがあるとします

public class KnownFriendsFilter{
  IList<People> _friends;
  public KnownFriendsFilter(IList<People> friends) {
    _friends = friends;
  }
  public IList<Person> GetFriends(IList<Person> people) {
    return people.Where(p=>_friends.Contains(p)).ToList();
  }
}

ここで、この特定のコンポーネントのアルゴリズムを少し変更する必要があるとします。たとえば、渡された最初のリストに異なる人物が含まれていることを確認したい場合などです。これは KnownFriendsFilter の懸念事項になるので、必ずクラスを変更してください。

ただし、このクラスとサポートする機能には違いがあります。

  • このクラスは、既知の友人のために人々の配列をフィルタリングするためのものです
  • それがサポートする機能は、人々の配列からすべての友達を見つけることです

違いは、機能が機能に関係しているのに対し、クラスは実装に関係していることです。その機能を変更するために受け取るほとんどの要求は、クラスの特定の責任の範囲外になります。

たとえば、文字「X」で始まる名前のブラックリストを追加したいとします (これらの人々は明らかに宇宙飛行士であり、私たちの友人ではないため)。これは機能をサポートするものですが、実際にはこのクラスの一部ではありません。クラスに固執するのは面倒です。次のリクエストが来たら、アプリケーションはミソジニーだけに使用され、女性の名前も除外する必要がある場合はどうなりますか? ここで、名前が男性か女性かを決定するロジックをクラスに追加する必要があります。または、少なくともその方法を知っている他のクラスについて知っておく必要があります。クラスは責任が大きくなり、非常に肥大化しています! また、分野横断的な懸念についてはどうでしょうか。ここで、人々の配列をフィルタリングするたびにログを記録したいと考えています。

IFriendsFilter インターフェイスを除外して、このクラスをデコレータでラップするか、IList の責任の連鎖として再実装することをお勧めします。そうすれば、それぞれの責任を、その懸念をサポートする独自のクラスに配置できます。依存関係を注入すると、このクラスを使用するコード (およびアプリケーションで中心的に使用されるコード) を変更する必要がまったくなくなります。

繰り返しになりますが、原則は既存のコードを決して変更しないということではありません。一般的に使用されるクラスの責任を肥大化させるか、それを使用するすべての場所を編集する必要があるかという決定に直面する状況に陥らないことです。

于 2009-09-13T00:14:16.997 に答える
1

では、今日の OCP は本当に理にかなっているのでしょうか? 私はそうは思わない。

時々それはします:

  • 基本クラスを顧客にリリースしたが、すべての顧客のマシンで簡単に変更できない場合 (たとえば、「DLL Hell」を参照)

  • あなたが基本クラスを自分で作成したのではなく、それを維持していない顧客である場合

  • より一般的には、基本クラスが複数のチームおよび/または複数のプロジェクトで使用される状況

コンウェイの法則も参照してください。

于 2009-09-13T00:03:51.380 に答える
1

興味深い質問です。オープン クローズド原則の厳密な定義に基づいて、あなたがどこから来ているかがわかります。

私はオープン・クローズの原則を少し違った形で定義するようになりました.この原則は適用されるべきだと思います.それはそれをはるかに広く適用することです.

私が言いたいのは、アプリケーションに関係するすべてのクラス (全体として) は、変更のために閉じて、拡張のために開く必要があるということです。したがって、原則として、アプリケーションの動作や操作を変更する必要がある場合、実際にはクラスを変更するのではなく、新しいクラスを追加してから、この新しいクラスを指すように関係を変更します (もちろん、サイズによって異なります)。変更の)。単一の責任に従い、制御の反転を利用している場合、これが発生するはずです。そのとき起こることは、すべての変更が拡張になるということです。それらのシステムは、以前の方法と新しい方法の両方で機能し、それらの間で変化する=関係を変えることができるようになりました.

于 2009-09-13T00:04:16.357 に答える
0

ここでのポイントは、このような最新のツールを使用すると、開発者は文字どおり数千行のコードを安全に数秒で変更できるということです。

「a」開発者がいる場合は問題ありません。チームで作業している場合、確かにバージョン管理、おそらく分岐とマージを使用している場合、さまざまな人からの変更がさまざまなファイルに集中する傾向があることを保証する機能は、何が起こっているかを制御できるようにするために非常に重要です.

3 つのリファクタリングを並行して実行し、分離されたファイルへの変更と同じくらい簡単にマージできる、言語固有のマージ/分岐ツールを想像できます。しかし、そのようなツールは存在しません。存在するとしても、私はそれらに依存したくありません。

于 2009-09-13T00:09:18.983 に答える