問題タブ [open-closed-principle]

For questions regarding programming in ECMAScript (JavaScript/JS) and its various dialects/implementations (excluding ActionScript). Note JavaScript is NOT the same as Java! Please include all relevant tags on your question; e.g., [node.js], [jquery], [json], [reactjs], [angular], [ember.js], [vue.js], [typescript], [svelte], etc.

0 投票する
1 に答える
144 参照

design-patterns - 継承に基づく API は OCP に違反しますか? これはプロバイダー モデル/依存性注入で実現できますか?

初めて API を設計し、SOLID ガイドラインに従おうとしています。私が苦労していることの 1 つは、OCP とテスト容易性と、単純さと拡張性の容易さとのバランスを取ることです。

このオープンソース API は、科学的なモデリングと計算を対象としています。目的は、さまざまなグループが特定のモデルをこの「プラグ可能な」アーキテクチャに簡単にインポートできるようにすることです。したがって、プロジェクトとしての成功は、これらの科学者が不必要なオーバーヘッドや急な学習曲線なしでドメイン固有の知識を容易に伝えることができるかどうかにかかっています。

たとえば、計算エンジンは「ベクトル化された」計算に依存しています。1 つのスカラー値だけを計算する必要はほとんどありません。多くのモデルはこれを利用して「オーバーヘッド」計算を実行し、各スカラー サブ計算で再利用できます。しかし、ユーザーがデフォルトのベクトル化動作を継承する (または別の方法で提供される) 単純なスカラー操作を定義できるようにしたいと考えています。

私の目標はそれを作ることでした

1) 初心者ユーザーが基本的な計算モデルをできるだけ簡単に実装できるようにする 2) 上級ユーザーがベクトル化動作をオーバーライドできるようにできるだけ簡単にする

...もちろん、SoC、テスト容易性などを維持しながら。

いくつかの改訂の後、シンプルでオブジェクト指向のものになりました。計算コントラクトはインターフェイスを介して定義されますが、ユーザーは、デフォルトのベクトル化を提供する抽象 ComputationBase クラスから派生することをお勧めします。以下は、デザインを縮小したものです。

ComputationBase のベクトル化された Compute には、もともと (コンストラクター DI を介して) プロバイダー パターンを使用していましたが、スカラーの Compute は抽象化したままにしました。基本クラスは常にベクトル化操作を「所有」しますが、注入されたプロバイダーに計算を委譲します。これは、テスト容易性とベクトル化コードの再利用の観点からも、一般的に有益であると思われました。ただし、これには次の問題がありました。

1) スカラー (継承) およびベクトル (プロバイダー) 計算のアプローチの不均一性は、ユーザーを混乱させる可能性が高く、要件に対して過度に複雑に見え、コードの悪臭を放っていました。

2) ベクトル化のために「別個の」プロバイダーを作成することは、漏れやすい抽象化でした。プロバイダーがスマートに何かを行う場合、通常、クラスの実装に関する内部知識が必要になります。それらを実装するためにネストされたプライベート クラスを作成していることに気付きました。

これは、OCP 対テスト容易性対シンプルさを考慮した適切なアプローチですか? 他の人は、さまざまなレベルの複雑さで拡張するために API をどのように設計しましたか? 私が含めたよりも多くの依存性注入メカニズムを使用しますか? また、この特定の例に対する回答と同じくらい、優れた API 設計に関する優れた一般的な参考文献にも関心があります。ありがとう。

ありがとう、デビッド

0 投票する
5 に答える
9973 参照

.net - Bootstrapper で Automapper を構成すると、Open-Closed 原則に違反しますか?

Bootstrapper で Automapper を構成していて、 で を呼び出してBootstrap()い ますが、新しいマッピングを追加する必要があるたびにクラスApplication_Start()を変更する必要があるため、これは間違っていると言われたので、Open-Closed Principle に違反しています。 Bootstrapper.

私は本当にこの原則に違反していると思いますか?

0 投票する
3 に答える
3883 参照

design-patterns - Factory Method パターンは Open/Closed 原則に違反していますか?

Factory Method パターン(Factory または Abstract Factory パターンと混同しないでください) は、Open/Closed の原則に違反していますか?

更新: 明確にするために、具象クラスに静的ファクトリ メソッドがあるシナリオについて言及しています。例 (これは FMP のウィキペディアのページからのものです):

プライベート コンストラクターは、クラスのサブクラス化、つまり拡張を妨げていませんか?

新しいファクトリ メソッドをサポートするためにクラスを変更する必要はありませんか? たとえば、クラスが最初に fromCartesian しかなく、後で fromPolar が必要になった場合、これをサポートするためにクラスを変更する必要はありませんでしたか?

これらは両方とも Open/Closed に違反していませんか?

0 投票する
2 に答える
1150 参照

c# - IoC と Dependency Injection を使用して、Open-Closed 原則に違反することなく、実装の新しいレイヤーでコードをラップする方法は?

Open Closedの原則に違反しないように、これが実際にどのように行われるかを理解しようとしています。

URL を受け取り、html を文字列として返すファイルをダウンロードする 1 つの関数を持つ HttpFileDownloader というクラスがあるとします。このクラスは、関数を 1 つだけ持つ IFileDownloader インターフェイスを実装します。したがって、コード全体で IFileDownloader インターフェイスへの参照があり、IFileDownloader が解決されるたびに HttpFileDownloader のインスタンスを返す IoC コンテナーがあります。

その後、しばらく使用すると、その時点でサーバーがビジー状態になり、例外がスローされることがあることが明らかになります。これを回避するために、例外が発生した場合は 3 回自動再試行し、各再試行の間に 5 秒待機することにしました。

そこで、最大 3 ループの for ループで HttpFileDownloader を使用し、各ループ間で 5 秒間待機する 1 つの関数を持つ HttpFileDownloaderRetrier を作成します。HttpFileDownloadRetrier の「再試行」機能と「待機」機能をテストできるように、HttpFileDownloaderRetrier コンストラクターに IFileDownloader を取得させることで、HttpFileDownloader 依存関係を注入しました。

したがって、IFileDownloader のすべての解決で HttpFileDownloaderRetrier が返されるようにします。しかし、そうすると、HttpFileDownloadRetrier の IFileDownloader 依存関係は、HttpFileDownloader ではなく、それ自体のインスタンスを取得します。

したがって、IFileDownloaderNoRetry という名前の HttpFileDownloader 用の新しいインターフェイスを作成し、HttpFileDownloader を変更してそれを実装できることがわかります。しかし、それは、Open Closed に違反する HttpFileDownloader を変更していることを意味します。

または、IFileDownloaderRetrier という名前の HttpFileDownloaderRetrier 用の新しいインターフェイスを実装してから、IFileDownloader の代わりにそれを参照するように他のすべてのコードを変更することもできます。しかし、繰り返しになりますが、他のすべてのコードで Open Closed に違反しています。

それで、私はここで何が欠けていますか?既存のコードを変更せずに、既存の実装 (ダウンロード) を実装の新しいレイヤー (再試行と待機) でラップするにはどうすればよいですか?

それが役立つ場合のコードは次のとおりです。

0 投票する
1 に答える
317 参照

open-closed-principle - オープンクローズ原則、リファクタリング

OCP をコード スニペットに適用しようとしていますが、現在の状態では非常に臭いですが、最後まで到達していないと感じています。

現在のコード:

それは本当に醜いです、私の新しいアプローチは次のようになります:

新しい SomeObject 型が登場したら、その特定のオブジェクトを格納する方法を実装する必要があります。これにより、OCP が壊れてしまい、モデル クラスを変更する必要があります。

ストア ロジックを SomeObject に移動するのも間違った原因だと感じているので、SRP に違反します (?)。

Store の実装が欠落している SomeObject の新しい実装が登場すると、Model クラスの Store メソッドで例外が発生し、実行時エラーが発生します。これもコードの匂いのように感じます。

これは、呼び出しコードが次の形式になるためです。

シーケンス オブジェクトの特定の型はわかりません。

OCP の概念を理解できないようです。車/果物の例以上の具体的な例やリンクはありますか?

0 投票する
1 に答える
157 参照

c# - C# を使用してこのアプリに Open-Closed Principle を適用する最も適切な方法は何ですか?

シナリオ

毎晩、約 100 万件の顧客契約について一連の計算を実行します。各コントラクトは、約 10 個の製品のグループの 1 つに関連付けられており、実行される一連の計算のバリエーションを使用する場合があります (ただし、全体の流れはほぼ同じです)。特定の製品のすべての契約は、特定の夜に同じ計算セットを使用します。分布は不均一ですが、最小の製品で数千から最大の製品で数十万に及びます。

時間が経つにつれて、新しい同様の (ただし同一である可能性は低い) 製品が追加され、既存の製品は、採用されているアルゴリズムにバリエーションを導入することによって調整される場合があります。(ちなみに、コードを変更することなく、アルゴリズムをパラメトリックに変更できると思います)。

これをサポートするために使用するコア「エンジン」は、製品開発と生産の両方に適用できる必要があります。後者は、何を受け入れるか、変更が一般的にどのように管理されるかについて非常に慎重な運用担当者によって管理されます。

アーキテクチャを検討する際に、私はOpen-Closed Principleに強く惹かれます。

ソフトウェア エンティティは、拡張に対してはオープンである必要がありますが、変更に対してはクローズされている必要があります。

C# での実装を計画しているので、関数をコアの外部で定義し、テキスト形式でロードし、現在のバージョンの製品定義の管理下にある製品の実行の開始時にコンパイルすることを規定することを検討しています。 . これらの各コンポーネントは、アプリケーションのコンパイル済み要素で定義されているインターフェイス (または同等のもの) を実装するクラスにコンパイルされます。リグレッション テストの範囲が大幅に縮小されるため、運用の観点からはプラスになると楽観視しています。

質問)

これは理にかなっていますか?潜在的な落とし穴について賢明なアドバイスを提供できる人はいますか?

私は依存性注入を再発明していますか?たとえば、毎回新しい DLL を提供することで、定期的な変更を提供することをお勧めしますか? もしそうなら、それは私たちの毎日の製品開発プロセスをどれだけ悪化させますか?

それとも、よりアジャイルなアプローチを取り、1 つの製品をエンド ツー エンドで構築し、他の製品を順番に追加して、リファクタリングによってどのようなアーキテクチャが出現するかを確認する必要がありますか?

あなたがまだ私と一緒にいるなら、あなたの忍耐に感謝します...

0 投票する
3 に答える
496 参照

open-closed-principle - ビジネス ロジックが変更された場合、オープン クローズドの原則を尊重するにはどうすればよいですか?

システムにいくつかの大きな変更を行っています。SOLID の原則を尊重して、これらの新しいビジネス ロジック ルールを実装する最善の方法を知りたいです。

オープン/クローズの原則は、「拡張にはオープン、変更にはクローズ」と言いますが、変更するにはどうすればよいですか? つまり、古いビジネス ロジックを保持したくないということです。私の考えでは、「拡張」は主に「コードを変更する」ではなく「コードを追加する」ことを意味します。

0 投票する
3 に答える
1122 参照

c# - 抽象メソッドとオープンクローズの原則

次の不自然なコードがあるとします。

クラスだけを見ていると、それがそれ自体で何かを実行し、オーバーライドしている基本メソッドを呼び出すため、オープン/クローズの原則に従っているLevel2ことがすぐにわかります。Level2.PrintHierarchy

ただし、Level1クラスだけを見ると、呼び出されないため、OCPに違反しているように見えますbase.PrintHierarchy。実際、C#では、コンパイラは「抽象ベースメンバーを呼び出せません」というエラーでクラスを禁止しています。

Level1OCPに従っているように見せかける唯一の方法はRoot.PrintHierarchy、空の仮想メソッドに変更することですが、そうすると、実装する派生クラスを強制するためにコンパイラーに依存できなくなりますPrintHierarchy

ここでコードを維持しているときに私が抱えている本当の問題は、をoverride呼び出さない多数のメソッドが表示されることですbase.Whatever()base.Whateverが抽象である場合は問題ありませんが、そうでない場合は、Whateverメソッドが具体的なオーバーライド可能なメソッドではなく、インターフェイスにプルされる候補になる可能性があります。または、クラスまたはメソッドを他の方法でリファクタリングする必要がありますが、ちなみに、それは明らかにデザインが悪いことを示しています。

抽象的であることを覚えRoot.PrintHierarchyたり、中にコメントを入れたりする以外に、のように形成されたクラスがOCPに違反しLevel1.PrintHierarchyているかどうかをすばやく特定する他のオプションはありますか?Level1


コメントにはたくさんの良い議論があり、いくつかの良い答えもあります。私はここで何を尋ねるべきかを正確に理解するのに苦労していました。@Jon Hannaが指摘しているように、仮想メソッドが単に「実装する必要がある」と示す場合もあれば、「拡張する必要がある」という意味の場合もあります。ベースバージョンを呼び出せない場合は、私のデザインを壊してください!」ただし、C#は、抽象またはインターフェイスが明らかに「実装する必要がある」状況であることを除いて、どちらを意味するかを示す方法を提供していません。(コードコントラクトに何かがない限り、ここでは少し範囲外だと思います)。

ただし、言語に実装必要なデコレータと拡張が必要な​​デコレータがある場合、無効にできない場合は、単体テストで大きな問題が発生する可能性があります。そのような言語はありますか?これは契約による設計のように聞こえるので、たとえばエッフェルにあったとしても驚かないでしょう。

最終結果はおそらく@Jordãoが言うように、そしてそれは完全に文脈的です。しかし、私はまだ答えを受け入れる前に、しばらく議論を開いたままにするつもりです。

0 投票する
1 に答える
173 参照

oop - OCPに準拠したコードをどのように記述しますか?

私は最近、基本的な設計原理について学ぼうとしていますが、OCPは少し混乱しています。変更が発生した場合、既存の動作中のパーツを変更するよりも、システムを拡張する方が望ましいことは理にかなっています。しかし、これは、システムを設計する方法ではなく、システムに変更を実装する方法の原則ではありませんか?基本的に、すべてのコードがサブクラス化を使用して拡張できるようになっているのではありませんか?そして、どのようにコードを変更のために閉じることができますか?それは、変更を実装する人がそれを使用することを選択する方法に依存するだけではありませんか?

おそらく、OCPに従わないコードの例と、それが原則にどれほど正確に違反しているかは、私がこれを理解するのに最も役立ちます。

ありがとう

0 投票する
1 に答える
1873 参照

oop - BDD を使用する場合、オープン/クローズの原則に従うことには何か利点がありますか?

オープン/クローズの原則は、オブジェクトまたはメソッドの回帰を防止することに関するものと思われます。BDD を実践しているため、コードがテストでカバーされていることを考えると、これは冗長な要件のようです。さらに、言語レベルではなく API レベルで拡張性を要求することで、さらに複雑になるようです。