2010-11-20 1 views
1

私はまだC#とインターフェイスを使い始めていて、理解していると思っていました。混乱は、私はここのためのいくつかの明確化を求めていることを発見した場合、あなたはインターフェイスを作成し、持っているクラスを継承し、それ"Programming to an interface"のコンセプトを忘れてしまったと思います

public Interface ISomeInterface 
{ 
    //some methods/properties 
} 

public class FooClass : ISomeInterface 
{ 
    //implemented ISomeInterfaces methods/properties 
} 

からそして、あなたはあなたのプログラムのどこかの実装では、このクラスのオブジェクトを使用する場合

public class BarClass 
{ 
    private ISomeInterface _someInterface; 
    public BarClass(ISomeInterface someInterface) 
    { 
    _someInterface = someInterface; 
    } 
    //rest of class 
} 

私の混乱はなぜこのように設定されているのですか?私はこれを理解する

public class BarClass 
{ 
    private FooClass _fooClass; 
    public BarClass(FooClass fooClass) 
    { 
    _fooClass = fooClass; 
    } 
    //rest of class 
} 

何をしないのです:私は、私はタイプFooClassの新しいオブジェクトをインスタンス化するだけでなく、のようなコンストラクタでタイプFooClassのオブジェクトを使用していただろうと思いましたか?インターフェイスのオブジェクトを直接宣言するとは思わなかったのですか?

ありがとうございます。

答えて

7

BarClassは、ISomeInterfaceという特定の実装に密接に結合してはいけません。

あなたはこれを使用する場合:

public BarClass(FooClass fooClass) 

それはBarClassは、この特定のFooClassの実装と他には何もでのみ動作できることを意味します。あなたが使用している場合一方:

BarClassはもはやしっかり FooClassに結合されていない
public BarClass(ISomeInterface fooClass) 

。つまり、BarClassの消費者は、定義された契約(インタフェース)を尊重している限り、必要なインタフェースの実装をすべて通過できるようになります。したがって、FooClassFooClassのインスタンスを渡したければ、彼はFooClassに満足していなければ、彼自身の実装を書いてコンストラクタに渡してBarClassの視点から渡すことができます。これは絶対に透過的です変更する必要があります)。

クラス間の弱い結合は、アプリケーション全体を書き換えることなく、あるコンポーネントを別のコンポーネントに簡単に置き換えることができるため、OOPの最も基本的な側面の1つです。

1

FooClassが何かをデータベースに書き込んだとします。実際にデータベースを設定することなくBarClassをテストしたいと思っています。同じインターフェースを実装した別のTestFooを作成した場合は、データベースのふりをしてクラスをより簡単にテストできます。 BarClassは「本当の」FooClassと話していないことを知る必要はありません。

+0

TestFooのような新しいクラスを作成することは良い考えではありません。なぜ嘲笑しないの? –

+0

@Draco Ater、Mockingが一般的に好ましいですが、私はコンセプトの要点から気をそらしたくありませんでした。クラスが動的に生成されるか手作業で生成されるかにかかわらず、基本的なコンセプトは、機械的標準が建築機械の異なる互換部品の置換を可能にするように、あるものを別のものに置き換えることができるということです。ソフトウェアでは、特にテストを有効にするために非常に便利です。 –

0

C/C++の背景はありますか?そして、あなたは(あなたがISomeInterfaceという抽象基底クラスを持っていると仮定した場合)

private ISomeInterface _someInterface; 

はC++で

private: 
    ISomeInterface& _someInterface; 

のように書かれることを認識する必要があります。

これは、ISomeInterfaceを実装するオブジェクトへの参照を、そのようなオブジェクト自体ではなく格納していることを意味します。この利点は、ISomeInterfaceを実装するBarClassに任意のオブジェクトを渡すことができることです。ユニットテスト用。

+0

私はポインタを理解していますが、C#では、オブジェクト自身を渡すのではなく、ISomeInterfaceを実装しているオブジェクトへのポインタをどのようにすればよいでしょうか。私はあなたの説明のその部分を逃したと思う。 – pghtech

+0

インターフェイスに含まれていないメソッドが必要な場合は、別のインターフェイスが必要ですが、実際にはオブジェクトを渡す必要があります。しかし、私と他の人が言ったように、それはカップリングを増加させます。 ISomeInterfaceが "IDatabase"であるとしましょう。なぜMySqlDatabaseを渡す必要がありますか。あなたのクラスBarClassは、MySqlDatabaseだけでなく、IDatabaseを実装しているどのオブジェクトでも動作するはずです。これは、インプリメンテーションではなくインターフェイスに対してコーディングすることを意味します。 – Philipp

0

具体的な実装ではなくインターフェイス定義を使用することで、コードがより疎結合になりました。この手法は、依存性注入に使用されます。

また、これはFooClassを別々に実装する必要がある場合に便利です。具体的な実装を使用した場合は、FooClassと宣言したコードを変更する必要があります。インターフェイスに対するプログラミングは、そのような変更の影響からあなたを守りません。代わりにFooClassのISomeInterfaceにプログラムへの主な利点の

0

一つ、あなたはおそらくFooClassの実装を変えるかもしれないということです。たとえば、データベース駆動型ブログアプリケーションを考えてみます。

interface IBlogStorage{ 
    getPosts(); 
} 

あなたは、その後のようなクラスがあります。

class XMLBlogSotrage: IBlogStorage{} 

を、あなたがインターフェイスにすべてを実装したとします。後で、そして、あなたはXMLが遅すぎると思うあなたはRDBMSを使用したい:

class MsSQLBlogStorage:IBlogStorage{} 

この場合は、あなたが他のコードに何も変更する必要はありません、あなただけの新しいクラスを作成する必要があり、プラグイン!それらはすでに存在していたコードで、ストレージがどこにあるのか気にする必要はありません。

0

インターフェイスとクラスの相互作用について考えるもう一つの方法は、それらを逆さにすることです。つまり、クラスを最初に始めることを意味します。たとえば、「Sort()」というメソッドを公開するクラスが複数あるとします。次に、これらのクラスへの参照を必要とするメソッドを持つ別のクラスがあり、そのメソッドは "Sort()"メソッドを呼び出します。パラメータが異なる複数のメソッドを持つ代わりに、それらのクラスにインターフェイスを作成して接続することができます(これらのクラスにはすでに実装が含まれているため、非常に簡単に修正できます)。

A.Sort() 
B.Sort() 
C.Sort() 

interface ISortable {void Sort();} 
A : ISortable 
B : ISortable 
C : ISortable 

D.SortSomething(ISortable foo) 
{ 
     foo.Sort() 
} 

これはあまりにも抽象的です。私の好きなインターフェイスの使用は、クラスをforeachループに参加させることです。

class SomeCollection : IEnumerable 
{ 
     List<SomeItem> _items = new List<SomeItem>(); 

     // This is the only code I need to enable this class to participate in foreach loop. 
     public Enumerator GetEnumerator() 
     { 
      return _items.GetEnumerator(); 
     } 
} 

インターフェイスがコードを簡素化できる方法を発見したら、クラスを作成する前にインターフェイスを作成することもできます。

関連する問題