web-dev-qa-db-ja.com

設計パターン-なぜインターフェースが必要なのですか?

OK。デザインパターンを学んでいます。誰かがインターフェイスを使用するデザインパターンの例をコーディングするのを見るたびに。次に例を示します。

http://visualstudiomagazine.com/Articles/2013/06/18/the-facade-pattern-in-net.aspx?Page=1

誰かがこの例でファサードパターンを示すためにインターフェースが必要だった理由を私に説明できますか?クラスをインターフェースではなくファサードに渡すと、プログラムは機能します。私がインターフェースを持っていない場合、それは意味します

4
Kyle Johnson

インターフェイスはデザインパターンとは無関係です。それらはオブジェクト指向についてです。オブジェクト指向では、オブジェクトのタイプは、その動作によって、つまり、オブジェクトが話すプロトコル(そのメソッド)によって定義されます。

JavaやC#などの言語のクラスは、動作(メソッド)に加えて表現(フィールド)も定義します。OOの基本的な原則の1つは、そのオブジェクトcannot他のオブジェクトの表現を知っていますevensameタイプのクラスです。ただし、クラスをタイプとして使用する場合、同じclass canprivateフィールドであっても、他のオブジェクトの表現を知っています。したがって、クラスを型として使用するとOOが壊れます。(残念ながら、JavaとC#、クラスareタイプ。)

JavaまたはC#でオブジェクト指向プログラミングを行う唯一の方法は、クラスonlyをファクトリとして使用することです(つまり、onlyの直後にnew)およびneverを型として(つまり、フィールドの型、メソッドの戻り型またはパラメーター型、またはジェネリック型への型引数として、決してクラスにキャストせず、決して使用しないinstanceofを使用します。また、型として、クラスではなくonlyインターフェースを使用します(Javaでは間違いなくプリミティブではありません)。

それがインターフェイスの機能です。これらは、JavaおよびC#でオブジェクト指向プログラミングを可能にします。これらがなければ、OOPはこれらの言語では不可能です。

3
Jörg W Mittag

契約のようなインターフェースを考えてください。これは、「これらのクラスは、これらの一連のルールに従う必要がある」という言い方です。

例を使ってIAnimalと呼びましょう。インターフェースはRunWalkの2つのメソッドを定義していると言えます。これは、「IAnimalを実装するクラスでRun、Walkなどを呼び出せなければならない」と言う方法です。

なぜこれが便利なのですか?たとえば、オブジェクトに対してRun and Walkを呼び出すことができる必要があるという事実に依存する関数を作成することができます。あなたは次のものを持つことができます:

public void RunThenWalk(Monkey m) {
    m.Run();
    m.Walk();
}

public void RunThenWalk(Dog d) {
    d.Run();
    d.Walk();
}

...そして、あなたが実行して歩くことができることがわかっているすべてのオブジェクトに対してそれを繰り返します。ただし、IAnimalインターフェイスを使用すると、次のように関数を1回定義できます。

public void RunThenWalk(IAnimal a) {
    a.Run();
    a.Walk();
}

インターフェイスに対してプログラミングすることにより、インターフェイスの意図を実装するクラスを本質的に信頼することになります。したがって、この例では、「私は気にしないhow彼らは走って歩く限り、走って歩く。私のRunThenWalkは、それらがその合意を満たす限り有効です。それは機能します。クラスについて他に何も知らなくても完璧にうまくいきました。」

13
Larsenal

インターフェースの主な目的は、コードを特定のものではなく抽象的なものにすることだと考えることができます。強力な型安全性を備えた言語では、どの型が使用されているかを知る必要なく、類似性のある複数のクラスを同じように扱うことができます。

たとえば、いくつかの子クラスが拡張されるPeopleのインターフェースを持つことができます。次に、人を扱うメソッドを用意し、Peopleを実装する任意またはすべてのタイプのクラスを受け入れ、それ以外のことについては何も心配しません。これは、他の形式の継承によっても提供されますが、インターフェイスには、それら自体が実装できないという特別な制限があります。

3
Southpaw Hare

私はあなたがリンクした記事の観点からそれを説明しようとします:インターフェイスの使用により、VehicleFacadeの単体テストを作成し、そのクラスを分離してテストすることが可能になります。これは、実際のIEngineControllerITransmissionControllerなどを使用する代わりに、EngineControllerTransmissionControllerなどのモック実装を提供することで実現できます。

もちろん、これらのインターフェイスを使用すると、さまざまなエンジンコントローラ、さまざまなトランスミッションコントローラなどからさまざまな車両を作成し、それらを自由に組み合わせることができます。ただし、実際のシナリオでは、最初の使用例(テスト)が2番目の使用例よりもはるかに頻繁に発生することを期待しています。

0
Doc Brown

私は Larsenal がこれまでのところ最良の答えを与えたと思いますが、それを拡張して、実用的なエンタープライズレベルのコード(C#ではなく、別のECMAScriptベースの言語)の具体的な例を示します。 。私のコードでは、根本的に異なるクラスを、クライアントコードの観点からは同じであるかのように扱うことができます。

私のアプリケーションでは、nextPage()、previousPage()などの関数を定義するIPagingインターフェイスがあります。このインターフェイスは、ビュークラスだけでなく、コントローラークラスによっても実装されます。これが私にできることは、bootstrapアプリケーションのcurrentPaging変数に渡されるIPagingを直接実装するビューを持つアプリケーションです。コントローラーにデータがロードされている間、このビューはすでに稼働しています。これにより、ユーザーの目の前でインタラクティブな何かがすぐに得られます。

それらがそのビューを通過すると、アプリケーションのcurrentPaging変数に、IPagingを実装するコントローラーのインスタンスが与えられます。次に、そのコントローラーは、IPagingビューで同じ関数を呼び出すことでIPagingを実装するか(ネストされた階層ナビゲーションを可能にするIPagingビューが内部にある可能性があります)、またはデータのページをビューにスワップアウトすることにより、別の方法でIPagingを実装する場合がありますそれはIPagingとは何の関係もありません。選択肢は文字通り無制限であり、取得した要件に基づいてわずかにまたは非常に異なるようにカスタマイズされたビューまたはコントローラーで同じアプリケーションフレームワークを使用できます。そして、私たちのクライアントは、ほとんどのクライアントと同様に、ナットです-したがって、私たちはできるだけ柔軟でなければなりません。

実装が1つまたは2つしかないときにインターフェイスを使用したことを後悔したことはありませんが、同じ基本クラスから継承しない実装が必要で、インターフェイスを使用しなかった場合は、インターフェイスを使用しなかったことを心から後悔しています。そして、特定のクラスへの参照がコードベース全体に広がり、複数のプロジェクトから参照されると、魔神をボトルに戻すのは困難です。

私が使用する言語で取得するインターフェイス(C#でも使用できると思われる)の利点の1つは、実行時に外部ソースから使用するインターフェイスの実装に読み込むことを選択できることです。ロードするアプリケーションは、ロードされた実装のクラス定義でコンパイルする必要はありません。インターフェイスにキャストできるようにするためには、インターフェイスの定義のみが必要です。インターフェースは、定義上、実質的にコードがありません。

0
Amy Blankenship

あなたが参照した記事は、インターフェースが便利になる理由を理解するための恐ろしい例です。インターフェースの有用性についての「あは」の瞬間がようやく出るまでに、非常に長い時間がかかりました。その理由は、私が参照した記事と同じように、インターフェースがサウンドアクション指向にひねられた名誉ある基本クラスであると思っていたからです。インターフェースについて述べているほとんどの記事が同じことをするので、私がこの誤解を持っていたのも不思議ではありません。

私が「鑑賞する」インターフェースに関して持っていた問題は、それらが最も理にかなっているので、それらが常に抽象基本クラスに変形するように見えることでした。代わりの方法は、インターフェイスを宣言し、具体的な派生クラスがすべて共有する多くの一般的なメソッドを実装したインターフェイスの派生(ベース)クラスを宣言することでした。ほとんどすべてのインターフェイスに2つのクラスを用意しても、1つが提供するときに配管を提供するだけでは意味がありませんでした。そのため、インターフェースは必然的に単純な抽象基本クラスに切り替わりました。

インターフェイス名が「アクション指向」であるにもかかわらず、実際には別の名前の基本クラスにすぎないことに気付いたとき、「あは」の瞬間が起こりました。したがって、IEngineControllerは実際にはインターフェイスではなく、EngineControllerBaseクラスです。私が気付いたのは、インターフェースが派生クラスの実装に結び付けられていない場合に、インターフェースが最も有用であるということです。代わりに、それら自体で明確なアクションまたは機能を記述します。

したがって、IStartControllerは、IStartStoppable ORに2つの別々のインターフェースさえあります。IStartable、IStoppableです。美化された抽象基本クラスの段階としてインターフェースを定義すると、インターフェースの価値が輝き始めます。

0
Dunk