オブジェクト指向パラダイムで、疎結合と密結合の違いを正確に説明できる人はいますか。
密結合は、クラスのグループが互いに強く依存している場合です。
このシナリオは、クラスがあまりにも多くの責任を引き受けるとき、または1つの懸念が独自のクラスを持つのではなく、多くのクラスにわたって広がるときに発生します。
疎結合は、単一責任と懸念の分離を促進する設計によって達成されます。
疎結合クラスは、他の(具体的な)クラスとは無関係に消費およびテストできます。
インターフェースは、デカップリングに使用するための強力なツールです。クラスは他の具象クラスではなくインタフェースを介して通信できます。また、インタフェースを実装するだけで、任意のクラスをその通信の反対側に置くことができます。
密結合の例
class CustomerRepository
{
private readonly Database database;
public CustomerRepository(Database database)
{
this.database = database;
}
public void Add(string CustomerName)
{
database.AddRow("Customer", CustomerName);
}
}
class Database
{
public void AddRow(string Table, string Value)
{
}
}
疎結合の例:
class CustomerRepository
{
private readonly IDatabase database;
public CustomerRepository(IDatabase database)
{
this.database = database;
}
public void Add(string CustomerName)
{
database.AddRow("Customer", CustomerName);
}
}
interface IDatabase
{
void AddRow(string Table, string Value);
}
class Database : IDatabase
{
public void AddRow(string Table, string Value)
{
}
}
別の例 ここ 。
帽子は体と「ゆるく結合」しています。つまり、人や体に何も変更を加えることなく帽子を簡単に外すことができます。あなたがそれをすることができるとき、あなたはそれから「疎結合」を持ちます。詳しくは下記をご覧ください。
あなたの肌を考えてください。体にくっついています。手袋のようにフィットします。しかし、もしあなたが肌の色を例えば白から黒に変えたいとしたら?肌をはがして染めてから貼り付けるなどの作業がどれほど痛みを伴うか想像できますか。それはあなたの体に密接に結合されているのであなたの肌を変えることは困難です。簡単に変更することはできません。これを可能にするためには、基本的に人間を再設計しなければならないでしょう。
神は良いオブジェクト指向プログラマーではありませんでした。
今度は朝服を着ることを考えなさい。あなたは青が好きではありませんか?問題ありません。代わりに赤いシャツをかぶることができます。シャツはあなたの肌と同じようにあなたの体に実際に接続されていないため、あなたはこれを簡単かつ楽に行うことができます。 シャツは自分の体がどうなっているのかわからないし気にもしていません。つまり、体を変えることなく、自分の服を変えることができます。
それが一言で言えば基本的な概念です。
ソフトウェアは常に変化するので重要です。一般的に言って、あなたはあなたのコードを簡単に修正できるようにしたいのです。 (これは別のコーディングのベストプラクティス、つまり開閉の原則と結び付いています。つまり、基本的に何も変更することなくコードに簡単に追加できるはずです(インターフェイスを使用することでこれが可能なことは可能です)。別の日のために)。
つまり、疎結合によってコードの変更が容易になります。上記の答えはこの時点で読む価値があるいくつかのコードを提供します。
写真の帰属 。
オブジェクト指向設計では、結合量は、あるクラスの設計が別のクラスの設計にどれだけ依存するかを表します。言い換えれば、クラスAの変更はクラスBの変更に関連した変更をどのくらいの頻度で実行するのでしょうか。タイトカップリングは、2つのクラスがしばしば一緒に変わることを意味し、ルーズカップリングは、それらがほとんど独立していることを意味します。一般に、テストと保守が容易なため、疎結合をお勧めします。
あなたは Martin Fowlerによるこの論文(PDF) が役に立つかもしれません。
一般的にタイトカップリングは悪いですが、ほとんどの場合、コードの柔軟性と再利用性を低下させるため、変更をはるかに困難にし、テスト容易性を妨げます。
密結合オブジェクトは、互いについてかなりよく知っておく必要があるオブジェクトであり、通常、他のインターフェースに大きく依存しています。密結合アプリケーションで1つのオブジェクトを変更するには、他の多くのオブジェクトを変更する必要があります。小さなアプリケーションでは、変更を簡単に識別でき、何も見逃す可能性が少なくなります。しかし、大規模なアプリケーションでは、これらの相互依存関係がすべてのプログラマーに常に知られているとは限らず、変更を見逃す可能性があります。しかし、疎結合オブジェクトの各セットは他のオブジェクトに依存しません。
つまり、疎結合は、あるコンポーネントの変更が他のコンポーネントの変更を必要とするリスクを減らすことを目的として、システムのコンポーネント間の相互依存性を減らすことを目的とした設計目標です。疎結合は、システムの柔軟性を高め、保守性を高め、フレームワーク全体をより「安定的」にすることを目的とした、より一般的な概念です。
カップリングとは、ある要素が別の要素に持っている直接的な知識の程度のことです。例:AとB、BのみがAの動作を変更した場合にのみその動作を変更します。疎結合システムは、定義可能な要素に簡単に分割できます。
2つのオブジェクトが疎結合の場合、それらは相互作用することができますが、お互いの知識はほとんどありません。
疎結合設計により、変化を処理できる柔軟なOOシステムを構築できます。
オブザーバデザインパターンは、クラスを疎結合にする良い例です。 Wikipedia で見ることができます。
私が理解しているように、密結合アーキテクチャーは、疎結合アーキテクチャーと比較した場合、変更に対する柔軟性があまりありません。
しかし、疎結合アーキテクチャー、メッセージフォーマット、オペレーティングプラットフォーム、ビジネスロジックの見直しが相手先に影響を与えることはありません。システムが刷新のために停止された場合、もちろんもう一方の端はしばらくサービスにアクセスすることができないでしょうがそれ以外は、変更されていない端は刷新の前のようにメッセージ交換を再開できます。
カップリングについての私の ブログ記事 からの抜粋:
タイトカップリングとは何ですか: -
上記の定義と同様に、密結合オブジェクトは他のオブジェクトについて知る必要があるオブジェクトであり、通常は互いのインターフェースに大きく依存しています。
密結合アプリケーションで1つのオブジェクトを変更すると、他の多くのオブジェクトも変更する必要があります。小さなアプリケーションでも問題はありません。変更を簡単に識別できます。しかし、大規模なアプリケーションの場合、これらの相互依存関係がすべてのコンシューマや他の開発者に常に知られているわけではないか、将来変更される可能性が多くあります。
密結合を理解するために、ショッピングカートのデモコードを見てみましょう。
namespace DNSLooseCoupling
{
public class ShoppingCart
{
public float Price;
public int Quantity;
public float GetRowItemTotal()
{
return Price * Quantity;
}
}
public class ShoppingCartContents
{
public ShoppingCart[] items;
public float GetCartItemsTotal()
{
float cartTotal = 0;
foreach (ShoppingCart item in items)
{
cartTotal += item.GetRowItemTotal();
}
return cartTotal;
}
}
public class Order
{
private ShoppingCartContents cart;
private float salesTax;
public Order(ShoppingCartContents cart, float salesTax)
{
this.cart = cart;
this.salesTax = salesTax;
}
public float OrderTotal()
{
return cart.GetCartItemsTotal() * (2.0f + salesTax);
}
}
}
上記の例の問題
タイトカップリングはいくつかの問題を引き起こします。
ここでは、OrderTotal()
メソッドは、カートの現在の商品の全額を表示します。このカートシステムに割引機能を追加したい場合。上記のコードでは、クラスが非常に密接に関連しているため、クラスごとに変更を加える必要があるため、実行するのは非常に困難です。
それらのライブラリを通して依存性注入を提供する特定のツールがあります。例えば、.netには ninject Library があります。
もしあなたがJavaでさらに進んでいるのであれば spring はこの機能を提供します。
疎結合オブジェクトは、コードにインタフェースを導入することで作成できます。それが、これらのソースが行うことです。
あなたが書いているあなたのコードで言う
Myclass m = new Myclass();
あなたのメソッドのこのステートメントはmyclass
に依存していると言っています。これは密結合と呼ばれます。今、あなたはいくつかのコンストラクタインジェクション、またはプロパティインジェクションとインスタンス化オブジェクトを提供し、それは疎結合になります。
疎結合は、2つの要素間の依存度が非常に低いことを意味します。
例:GSM SIM
密結合は、2つのコンポーネント間の依存度が非常に高いことを意味します。
例:CDMAモバイル
密結合は、あるクラスが別のクラスに依存していることを意味します。
疎結合は、1つのクラスがクラスではなくインターフェースに依存していることを意味します。
密結合では、メソッド内で宣言されたハードコーディングされた依存関係があります。
疎結合では、ハードコードではなく実行時に依存関係を外部に渡す必要があります。 (疎結合システムでは、クラスとの依存関係を減らすためにインタフェースが使用されます。)
たとえば、JSON出力、CSV出力など、複数の方法で出力を送信できるシステムがあります。
public interface OutputGenerator {
public void generateOutput();
}
public class CSVOutputGenerator implements OutputGenerator {
public void generateOutput() {
System.out.println("CSV Output Generator");
}
}
public class JSONOutputGenerator implements OutputGenerator {
public void generateOutput() {
System.out.println("JSON Output Generator");
}
}
// In Other Code, we write Output Generator like...
public class Class1 {
public void generateOutput() {
// Here Output will be in CSV-Format, because of hard-coded code.
// This method tightly coupled with CSVOutputGenerator class, if we want another Output, we must change this method.
// Any method, that calls Class1's generateOutput will return CSVOutput, because Class1 is tight couple with CSVOutputGenerator.
OutputGenerator outputGenerator = new CSVOutputGenerator();
output.generateOutput();
}
}
上の例で、JSONの出力を変更したい場合は、Class1がCSVOutputGeneratorクラスと密接に関連しているため、コード全体を見つけて変更する必要があります。
public interface OutputGenerator {
public void generateOutput();
}
public class CSVOutputGenerator implements OutputGenerator {
public void generateOutput() {
System.out.println("CSV Output Generator");
}
}
public class JSONOutputGenerator implements OutputGenerator {
public void generateOutput() {
System.out.println("JSON Output Generator");
}
}
// In Other Code, we write Output Generator like...
public class Class1 {
public void generateOutput(OutputGenerator outputGenerator) {
// if you want to write JSON, pass object of JSONOutputGenerator (Dependency will be passed externally to this method)
// if you want to write CSV, pass object of CSVOutputGenerator (Dependency will be passed externally to this method)
// Due to loose couple with class, we don't need to change code of Class1, because Class1 is loose coupled with CSVOutputGenerator or JSONOutputGenerator class
// Any method, that calls Class1's generateOutput will desired output, because Class1 does not tight couple with CSVOutputGenerator or JSONOutputGenerator class
OutputGenerator outputGenerator = outputGenerator;
output.generateOutput();
}
}
それはクラスについてです依存率疎結合でとても低く、密結合でとても高い別のクラス。 サービス指向アーキテクチャーで明確になるように、サービスは互いに疎結合ですモノリシックお互いに対してどのクラスの依存関係が意図的であるかに対して
疎結合は、密結合が直接的に与えられる場合には、依存関係のすべての情報を提供せずに間接的にクラスが必要とする依存関係を与えるプロセスです。これはコーディングの良い方法ではありません。
あるオブジェクトの作成/存在が、調整できない別のオブジェクトに依存している場合、その密接な関係があります。そして、依存関係を調整することができれば、それは疎結合です。 Javaの例を考えます。
class Car {
private Engine engine = new Engine( "X_COMPANY" ); // this car is being created with "X_COMPANY" engine
// Other parts
public Car() {
// implemenation
}
}
Car
クラスのクライアントは「X_COMPANY」エンジンのみでそれを作成することができます。
それを変える能力でこのカップリングを壊すことを考えなさい:
class Car {
private Engine engine;
// Other members
public Car( Engine engine ) { // this car can be created with any Engine type
this.engine = engine;
}
}
Car
は型で作成できるため、 "X_COMPANY"のエンジンには依存しません。
Java特有の注意:デカップリングの目的でJavaインターフェースを使用することは、適切な設計方法ではありません。 Javaでは、インターフェースは目的を持っています - 本質的に分離の振舞い/利点を提供するコントラクトとして機能すること。
承認された回答でのBill Rosmusのコメントには、良い説明があります。
アナロジーを使ってここにたくさんのいい答えがあります、しかし仕事の友人は私がここに述べられたもののすべてより好きであるという例を私に与えました...目とメガネ!
タイトカップリング
タイトカップリングが目になります。私が自分のビジョンを直したいのなら、私は目の移植を受けるのは非常に高価で、かなりのリスクを抱えています。しかし、デザイナー(人類)がより良い方法を見つけたらどうなるでしょう。それは簡単に変更することができるように体に疎結合されている機能を追加してください! (はい。メガネ)
疎結合
私は私の基本的な視野を壊すことなく私の眼鏡を簡単に交換することができます。私はメガネをはずすことができます、そして、私のビジョンはそれが以前であった方法になるでしょう(良くも悪くもありません)。異なるペアのメガネを使用すると、リスクとメンテナンス性がほとんどなく、私たちの目を通して世界を見る方法が変わります。
要約
それで、次回は「誰かが私のコードが密結合されているかどうかを気にかけていますか」とあなたに尋ねます。その答えは、変化への努力、維持への努力、そして変化のリスクです。
では、これはC#でどのように行われるのでしょうか。インターフェースと依存性注入
EDIT
これはDecoratorパターンの良い例でもあります。ここでは目が私たちがインターフェース要件を満たすことによって装飾しているクラスであるが、異なる機能を与えるクラスです(例:サングラス、老眼鏡、宝石商用虫眼鏡e.t.c)。