関数Fを実装するソフトウェアモジュールAがあるとします。別のモジュールBはF 'と同じ関数を実装します。
重複するコードを取り除く方法はいくつかあります。
これらのオプションはすべて、モジュール間の追加の依存関係を生成します。彼らは、カップリングの増加を犠牲にしてDRY原理を適用します。
私が見る限り、DRYを適用すると、カップリングは常に増加するか、または少なくとも、より高いレベルに移動します。ソフトウェア設計の最も基本的な2つの原則の間には矛盾があるようです。
(実際、そのような競合があるのは驚くべきことではありません。これが、優れたソフトウェア設計を非常に困難にしているものです。これらの競合は、通常、紹介文では扱われていません。
編集(説明のため):FとF 'の等式は単なる偶然ではないと思います。 Fを変更する必要がある場合、F 'も同じように変更する必要があります。
これらのオプションはすべて、モジュール間の追加の依存関係を生成します。彼らは、カップリングの増加を犠牲にしてDRY原理を適用します。
なぜそうなのか。しかし、それらはライン間の結合を減らします。得られるのは、カップリングを変更する力です。カップリングには多くの形式があります。コードを抽出すると、間接性と抽象化が向上します。良くも悪くもそれを増やすことができます。どちらを取得するかを決定する最も重要なことは、それに使用する名前です。名前を見たときに驚いたら、中を覗いても誰も好意を示したことはありません。
また、DRY=を単独でフォローしないでください。複製を中止すると、そのコードの2つの使用法が一緒に変更されることを予測する責任があります。それらが個別に変更される可能性が高い場合あなたは混乱と余分な作業を引き起こし、ほとんどメリットがありませんでした。しかし、本当に良い名前はそれをより口当たりの良いものにすることができます。
カップリングは、システムが分離されて機能するかどうか誰にもわからない場合を除いて、常に存在します。したがって、リファクタリングカップリングは、毒を選択するゲームです。次のDRYは、変更が非常に困難になるまで、同じ設計の決定を多くの場所で繰り返し表現することによって作成されるカップリングを最小化することで報われる可能性があります。しかしDRYあなたのコードを理解することを不可能にします。その状況を救う最良の方法は本当に良い名前を見つけることです。良い名前が思いつかない場合、私はあなたが熟練していることを望みます 無意味な名前の回避
明示的な依存関係を解除する方法があります。人気のあるものは、ランタイムに依存関係を注入することです。このようにして、静的な安全性を犠牲にしてDRYを取得し、カップリングを削除します。今日では非常に人気があり、人々は理解さえしていませんが、それはトレードオフです。たとえば、アプリケーションコンテナーは、複雑さを隠すことにより、日常的に依存関係管理を非常に複雑なソフトウェアに提供します。単純な古いコンストラクターの注入でさえ、型システムがないために一部の契約を保証できません。
タイトルに答えるために-はい、それは可能ですが、ランタイムディスパッチの結果に備えてください。
この方法では、他の各モジュールに依存するDのみが依存関係になります。
または、組み込みの依存関係注入を使用してアプリケーションコンテナーにCを登録し、ゆっくりと成長するランタイムクラスローディングループとデッドロックの自動配線の幸運を楽しんでください。
それ以上の文脈がない答えが意味をなすかどうかはわかりません。
A
はすでにB
に依存していますか、またはその逆ですか? —その場合、F
のホームを明確に選択できる可能性があります。
A
とB
は、F
の適切なホームになる可能性のある一般的な依存関係をすでに共有していますか?
F
の大きさ/複雑さはどれくらいですか? F
は他に何に依存していますか?
モジュールA
とB
は同じプロジェクトで使用されていますか?
とにかく、A
とB
は共通の依存関係を共有することになりますか?
使用されている言語/モジュールシステム:新しいモジュールは、プログラマーの負担で、パフォーマンスのオーバーヘッドでどれほど苦痛ですか?たとえば、モジュールシステムがCOMであるC/C++で記述している場合、ソースコードに問題が発生し、代替ツールが必要であり、デバッグに影響し、パフォーマンスに影響します(モジュール間呼び出しの場合)。少し間を置いてください。
一方、Javaまたは単一の実行環境でシームレスに結合するC#DLLについて話している場合、それは別の問題です。
関数は抽象化であり、DRYをサポートします。
ただし、適切な抽象化は完全である必要があります。不完全な抽象化は、使用しているクライアント(プログラマー)が基礎となる実装の知識を使用して不足分を補う可能性が非常に高くなります。
したがって、単一の関数を新しいモジュールA
に移動するだけではなく、B
およびC
に依存するためのより良い抽象化を作成することを検討します。
新しい抽象化を引き出すための一連の関数を探しています。つまり、コードベースがさらに進んで、1つではなく、より完全な、またはより完全な抽象化リファクタリングを特定するまで待つ場合があります。単一の関数コードで教えてください。
この問題を「最小化」できるすべての方法に焦点を当てたここでの答えは、あなたを傷つけています。また、単にカップリングを作成するさまざまな方法を提供する「ソリューション」は、真のソリューションではありません。
真実は、あなたが作成したまさにその問題を理解することに失敗しているということです。あなたの例の問題は、DRYとは関係なく、(より広くは)アプリケーション設計とは関係ありません。
モジュールAとBが両方とも同じ関数Fに依存しているのに、なぜ分離されているのか自問してみてください。もちろん、貧弱な設計に取り組むと、依存関係の管理/抽象化/結合/あなたの名前に問題が生じます。
動作に応じて適切なアプリケーションモデリングが行われます。したがって、Fに依存するAとBの部分は、独自の独立したモジュールに抽出する必要があります。これが不可能な場合は、AとBを組み合わせる必要があります。どちらの場合も、AとBはシステムで使用できなくなり、存在しなくなります。
DRYは、不十分な設計を明らかにするために使用できるプリンシパルであり、それを引き起こすことはありません。アプリケーションの構造が原因でDRY(whenそれが本当に当てはまる-あなたの編集に注意)を達成できない場合、それは構造が持っていることの明確な兆候ですこれが「継続的リファクタリング」も従うべき原則である理由です。
他のデザインプリンシパル(SOLID、DRYなど)のABCには、アプリケーションをより簡単にするallがchangeing(リファクタリングを含む)にするために使用されています。 thatに焦点を合わせると、他のすべての問題が消え始めます。
これらのオプションはすべて、モジュール間の追加の依存関係を生成します。彼らは、カップリングの増加を犠牲にしてDRY原理を適用します。
少なくとも3番目のオプションについては、私は別の意見を持っています。
あなたの説明から:
AとBの両方がすでにCの機能を必要としているため、FをCモジュールに配置しても、結合は増加しません。