インターフェイスを作成するタイミングを知るにはどうすればよいですか?


196

開発学習の途中で、インターフェイスについてもっと学ぶ必要があると感じています。

よく読んでいますが、なかなか理解できないようです。

私は次のような例を読みました:「基本」、「歩く」、「実行」、「GetLegs」などのIAnimalインターフェースを備えたもの-しかし、何かに取り組んだことがなく、「インターフェースを使用する必要がありますここに!"

何が欠けていますか?なぜ私が理解するのが難しいのですか?私はそれを具体的に必要としていることに気づかなかったかもしれないという事実に驚かされました。開発者という点で最高のものが足りないように感じます。もし誰かがこのような経験をしていて画期的な経験をしたなら、私はこの概念を理解する方法に関するいくつかのヒントに感謝します。ありがとうございました。


回答:


151

それはこの具体的な問題を解決します:

あなたは4つの異なるタイプのa、b、c、dを持っています。コード全体で次のようなものがあります:

a.Process();
b.Process();
c.Process();
d.Process();

なぜそれらにIProcessableを実装させないのですか?

List<IProcessable> list;

foreach(IProcessable p in list)
    p.Process();

これは、たとえば同じことをすべて行う50種類のクラスを追加すると、はるかに適切にスケーリングされます。


別の具体的な問題:

System.Linq.Enumerableを見たことがありますか?これは、IEnumerableを実装する任意の型で動作する大量の拡張メソッドを定義します。IEnumerableを実装するものは基本的に「順序付けられていないforeachタイプのパターンでの反復をサポートします」と書かれているため、列挙可能なタイプに対して複雑な動作(Count、Max、Where、Selectなど)を定義できます。


2
それは役立ちます。すべてのタイプにProcess()メソッドの実装があるだけでなく、インターフェースが存在することの利点は何ですか?
user53885 2009年

それらがすべて同じ基本型のサブクラスであるか、またはインターフェイスを実装していない限り、同じ変数pを使用することはできません。
Karl

Processメソッドを持つ50の異なるクラスとは対照的に、キャストする必要はありません。C#は「ダックタイピング」を使用しないため、AにProcess()があり、BにProcess()があるからといって、どちらも呼び出す一般的な方法があるわけではありません。そのためのインターフェースが必要です。
user7116 2009年

正しい。例をわかりやすくするために、「var」を「IProcessable」に変更しました。
ジミー

2
@ロジェリオ:私は一般的になろうとしていた。重要なのは、「Process()関数を持つものがあるとき」ではなく、「メソッドの共通セットを共有するものがあるとき」ではありません。例は簡単に次のように変更できますforeach(IMyCompanyWidgetFrobber a in list) a.Frob(widget, context);
ジミー

133

私はジミーの答えがとても好きですが、何かを追加する必要があると感じています。全体の鍵は、IProcessの「可能」です。ことです。。これは、インターフェイスを実装するオブジェクトの機能(またはプロパティですが、C#プロパティの意味ではなく「本質的な品質」を意味します)を示します。IAnimalはおそらくインターフェイスの良い例ではありませんが、システムに歩けるものがたくさんある場合、IWalkableは良いインターフェイスになるかもしれません。犬、牛、魚、ヘビなどの動物から派生したクラスがあるかもしれません。最初の2つはおそらくIWalkableを実装しますが、後の2つは歩かないため、歩きません。次に、「犬と牛の派生元の別のスーパークラス、WalkingAnimalがないのはなぜですか」と尋ねます。答えは、継承ツリーの外に完全に歩行可能な、ロボットなどの何かがある場合です。ロボットはIWalkableを実装しますが、おそらく動物から派生したものではありません。歩くことができるもののリストが必要な場合は、

次に、IWalkableをIPersistableなどのソフトウェアに置き換えます。これにより、類推は実際のプログラムで見られるものに非常に近くなります。


9
私はあなたが思いついたことが好きです-「それは能力を示しています」。機能を定義する必要がある場合、インターフェイスは本当に必要です。なぜなら、基本はその「ベース」クラスに固執する必要があるからです。
Ramiz Uddin 2011年

71

同じ機能の実装が異なる場合は、インターフェースを使用します。

一般的な具象実装を共有する必要がある場合は、抽象/基本クラスを使用します。


8
最初のものはポリモーフィズムと呼ばれます。2つ目はヘビ油です。sublcass ベースクラスでない場合(Liskov置換の原則に違反しない場合)、継承よりも構成を優先する必要があります。
Arnis Lapsa

@ArnisLapsa「サブクラスがベースクラスでない限り」という意味がよくわかりません。サブクラスがベースクラスにならないのはいつですか?(isキーワードと同様)
Marc.2377

32

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

したがって、IAnimalの例では、「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();
}

インターフェースに対してプログラミングすることで、インターフェースの意図を実装するクラスを本質的に信頼することになります。したがって、私たちの例では、「私はどうでもいい彼らが走ったり歩く限り、彼らがに走ったり歩い。私のRunThenWalkは、それらがその合意を満たす限り有効です。クラス。"

この関連する質問にも良い議論があります。


1
実装の独立性を忘れないでください。インターフェースを使用すると、基礎となる関数がどのように実装されているかを気にする必要がなくなります。
Matthew Brubaker、

18

そんなに心配しないで。多くの開発者が、インターフェースを作成する必要はほとんどありません。.NETフレームワーク内で使用可能なインターフェースを頻繁に使用しますが、すぐにインターフェースを作成する必要がなければ、驚くことはありません。

私がいつも誰かに与える例は、あなたが帆船クラスと毒蛇クラスを持っている場合です。これらはそれぞれBoatクラスとCarクラスを継承します。ここで、これらすべてのオブジェクトをループしてそれらのメソッドを呼び出す必要があるとしましょうDrive()。次のようなコードを書くこともできます:

if(myObject is Boat)
    ((Boat)myObject).Drive()
else
    if (myObject is Car)
        ((Car)myObject).Drive()

書く方がはるかに簡単です:

((IDrivable)myObject).Drive()

16

Jimmyは、複数の型に対して単一の変数を使用できるようにしたいが、それらの型はすべて、インターフェース宣言を介して同じメソッドを実装する場合に、それを正しく行います。次に、インターフェイス型付き変数でメインメソッドを呼び出すことができます。

ただし、インターフェースを使用する2つ目の理由があります。プロジェクトアーキテクトが実装コーダーとは異なる人物である場合、または複数の実装コーダーと1人のプロジェクトマネージャーがいる場合。担当者は一連のインターフェース全体を作成してシステムが相互運用することを確認し、開発者がインターフェースに実装クラスを入力するようにします。これは、複数の人が互換性のあるクラスを書くことを保証する最良の方法であり、彼らは並行してそれを行うことができます。


15

軍の類推が好きです。

あなたがソフトウェア開発者ミュージシャン、または弁護士であるかどうか、軍曹は気にしません。
あなたは兵士として扱われます。

UML

それはだ簡単に彼は、と連携している人物の特定の細部を気にしない軍曹のための
兵士の抽象化として扱うすべての人(...と、彼らはもののように行動するために失敗したときにそれらを罰します)。

人が兵士のように振る舞う能力は多型と呼ばれます。

インターフェイスは、ポリモーフィズムの実現に役立つソフトウェア構造です。

シンプルさを実現するために詳細を抽象化する必要はあなたの質問への答えです。

語源的に「多くの形式」を意味する多態性は、基本クラスの任意のサブクラスのオブジェクトを、基本クラスのオブジェクトであるかのように扱う機能です。したがって、基本クラスには多くの形式があります。基本クラス自体、およびそのサブクラスのいずれかです。

(..)これにより、コードが記述しやすくなり、他の人が理解しやすくなります。また、他のサブクラスをタイプのファミリーに後で追加でき、それらの新しいサブクラスのオブジェクトも既存のコードで機能するため、コードを拡張可能にします。


14

私の経験では、モックフレームワークでユニットテストを開始するまで、インターフェイスを作成する原動力は発生しませんでした。インターフェースを使用することでモックがはるかに容易になることが明らかになりました(フレームワークは仮想メソッドに依存しているため)。始めたら、実装からクラスへのインターフェースを抽象化することの価値を見ました。実際のインターフェースを作成しなくても、今は自分のメソッドを仮想化しようとします(オーバーライド可能な暗黙のインターフェースを提供します)。

インターフェースへのリファクタリングの良い習慣を強化するために私が見つけた他の多くの理由がありますが、ユニットテスト/モッキングは実際的な経験の最初の「あは瞬間」を提供したものでした。

編集:明確にするために、ユニットテストとモックを使用して、私は常に2つの実装を持っています-実際の具体的な実装とテストで使用される代替のモック実装です。2つの実装ができたら、インターフェースの価値が明らかになります。いつでも実装を置き換えることができるように、インターフェースの観点から対処してください。この場合は、モックインターフェイスに置き換えます。私のクラスが適切に構築されていれば、実際のインターフェースなしでこれを実行できることはわかっていますが、実際のインターフェースを使用すると、これが強化され、よりクリーンになります(読者にとってより明確になります)。この推進力がなければ、ほとんどのクラスのみが単一の具象実装を持っているため、インターフェースの価値を高く評価したとは思いません。


間違った理由で正しいこと。あなたの場合-あなたはいわゆる「ヘッダーインターフェース」に終わり、太りすぎの複雑さを追加することでシンプルさが実現しました。
Arnis Lapsa

@Arnis-ユニットテストは「間違った理由」であり、テストで依存関係を削除するためにクラスを簡単に模倣することは「間違った理由」です。申し訳ありませんが、同意しません。
tvanfosson

1
テストは、コードがテスト可能であるかどうかにかかわらず、フィードバックを提供することによって間接的に設計に影響を与える必要があります。テストポイント自体を改善するために拡張ポイントを追加することは、不正行為のようなものです。Mark Seemanがそれを最高にまとめていると思います。ly/ esi8Wp
Arnis Lapsa

1
@Arnis-単体テストでモックを使用しますか?そうでない場合、依存関係への依存をどのように削除しますか?DIを使用していますか?単体テストでモックとDIを使うようになりました。あざけりとDIは、インターフェースを使用して契約を定義することの学術的理解がこれまで不可能であった良い実践の価値を証明しました。私のTDDの採用により、私のコードは他の方法よりもはるかに少ない結合になります。それは良いことだと思います。
tvanfosson

いわゆる自然関節に沿っていない分解は、凝集度が低く、不必要な複雑さをもたらすと言っているだけです。
Arnis Lapsa

10

プログラミングにおけるインターフェースの適切な使用法を理解するのに役立ついくつかの非プログラミング例。

電気機器と電気ネットワークの間にインターフェースがあります-それはプラグとソケットの形状とそれらを横切る電圧/電流に関する一連の規則です。新しい電気装置を実装したい場合、プラグがルールに従う限り、ネットワークからサービスを取得できます。これにより、拡張性が非常に簡単になり、調整のコストが削減または削減されます。新しいデバイスの動作について電力会社に通知したり、新しいデバイスをネットワークに接続する方法について個別に合意したりする必要はありません。

国によって標準のレールゲージがあります。これにより、レールを敷設するエンジニアリング会社と列車を建設するエンジニアリング会社がそれらのレールで走行するための分業が可能になり、システム全体を再設計することなく鉄道会社が列車を交換およびアップグレードできるようになります

ビジネスがクライアントに提供するサービスはインターフェースとして説明できます。明確に定義されたインターフェースはサービスを強調し、手段を隠します。あなたがメールボックスに手紙を入れたとき、あなたは、与えられた時間内に手紙を届けるために郵便システムを期待していますが、手紙の配信方法についての期待を持っていない:あなたが知っている必要はありませんし、郵便サービスがありへの柔軟性を要件と現在の状況に最適な配信方法選択します。これの例外は、航空便を選択する顧客の能力です。これは、実装の多くを明らかにしすぎているため、現代のコンピュータープログラマーが設計したインターフェイスの種類ではありません。

自然の例:eats()、makesSound()、move()などの例にはあまり熱心ではありません。それらは正しい振る舞いを説明しますが、相互作用とそれらがどのように有効にされるかについて説明しません。自然界での相互作用を可能にするインターフェースの明白な例は、繁殖に関係しています。たとえば、花はミツバチに特定のインターフェースを提供し、受粉を行うことができます。


5

.net開発者として一生かけて、独自のインターフェイスを作成することはまったく不可能です。結局のところ、私たちは何十年もそれらなしで問題なく生き残り、私たちの言語はまだチューリング完全でした。

インターフェースが必要な理由はわかりませんが、現在のプロジェクトでインターフェースを使用する場所のリストを提供できます。

  1. プラグインモデルでは、プラグインをインターフェイスごとにロードし、プラグインライターが準拠するインターフェイスを提供します。

  2. マシン間メッセージングシステムでは、メッセージクラスはすべて特定のインターフェースを実装し、インターフェースを使用して「アンラップ」されます。

  3. 私たちの構成管理システムは、構成設定を設定および取得するために使用されるインターフェースを定義します。

  4. 厄介な循環参照の問題を回避するために使用するインターフェイスが1つあります。(必要がない場合は、これを行わないでください。)

ルールがあると思いますが、is-a関係内で複数のクラスをグループ化したいが、基本クラスに実装を提供したくない場合は、インターフェースを使用することです。


5

コード例(Andrewと私の追加のものの組み合わせ) インターフェイスの目的が何であるかをもの)では、多重継承をサポートしていない言語の抽象クラスではなく、なぜインターフェイスであるかがわかります(c#およびjava):

interface ILogger
{
    void Log();
}
class FileLogger : ILogger
{
    public void Log() { }
}
class DataBaseLogger : ILogger
{
    public void Log() { }
}
public class MySpecialLogger : SpecialLoggerBase, ILogger
{
    public void Log() { }
}

FileLoggerとDataBaseLoggerはインターフェースを必要としないことに注意してください(Loggerの抽象基本クラスである可能性があります)。ただし、基本クラスの使用を強制するサードパーティのロガーを使用する必要があると考えてください(使用する必要のある保護されたメソッドを公開しているとしましょう)。言語は多重継承をサポートしていないため、抽象基本クラスのアプローチを使用できません。

結論としては、可能な場合はインターフェイスを使用して、コードの柔軟性を高めます。あなたの実装はより緊縛されていないので、それは変化によりよく適応します。


4

私は時々インターフェースを使用しましたが、ここに私の最新の使用方法があります(名前は一般化されています):

ビジネスオブジェクトにデータを保存する必要があるWinFormのカスタムコントロールがたくさんあります。1つの方法は、各コントロールを個別に呼び出すことです。

myBusinessObject.Save(controlA.Data);
myBusinessObject.Save(controlB.Data);
myBusinessObject.Save(controlC.Data);

この実装の問題は、コントロールを追加するたびに、「データの保存」メソッドに移動して新しいコントロールを追加する必要があることです。

SaveToBusinessObject(...)メソッドを持つISaveableインターフェイスを実装するようにコントロールを変更したので、「データの保存」メソッドはコントロールを反復処理し、ISaveableであるものを見つけると、SaveToBusinessObjectを呼び出します。したがって、新しいコントロールが必要になったとき、誰かがそのオブジェクトにISaveableを実装するだけで済みます(別のクラスに触れないでください)。

foreach(Control c in Controls)
{
  ISaveable s = c as ISaveable;

  if( s != null )
      s.SaveToBusinessObject(myBusinessObject);
}

多くの場合、インターフェースの実現されていない利点は、変更をローカライズすることです。いったん定義すると、アプリケーションのフロー全体を変更することはほとんどありませんが、詳細レベルで変更を行うことがよくあります。特定のオブジェクトの詳細を保持する場合、ProcessAの変更はProcessBの変更に影響しません。(基本クラスにもこの利点があります。)

編集:別の利点は、行動の特異性です。私の例のように、私がやりたいことはデータを保存することだけです。どのような種類のコントロールであるか、それが他に何ができるかは気にしません-データをコントロールに保存できるかどうかを知りたいだけです。これにより、保存コードがかなり明確になります。カスタムコントロールがすべてを処理するため、テキスト、数値、ブール値などのチェックはありません。


4

クラスの動作を強制する必要がある場合は、インターフェイスを定義する必要があります。

動物の行動には、歩く、食べる、走るなどが含まれる場合があります。したがって、動物をインターフェイスとして定義します。

別の実用的な例は、ActionListener(またはRunnable)インターフェースです。特定のイベントを追跡する必要がある場合は、それらを実装します。したがって、actionPerformed(Event e)クラス(またはサブクラス)のメソッドの実装を提供する必要があります。同様に、Runnableインターフェースの場合は、public void run()メソッドの実装を提供します。

また、これらのインターフェイスは、任意の数のクラスで実装できます。

インターフェースが(Javaで)使用される別の例は、C ++で提供される多重継承を実装することです。


3
インターフェースに関して、多重継承のようなことを言うのを止めさせてください。クラスのインターフェースを継承しないでください。あなたはそれを実装します。
AndreiRînea2009年

4

スリープ状態にしようとしたときに発生する可能性のある不快感をモデル化したいとします。

インターフェース前のモデル

ここに画像の説明を入力してください

class Mosquito {
    void flyAroundYourHead(){}
}

class Neighbour{
    void startScreaming(){}
}

class LampJustOutsideYourWindow(){
    void shineJustThroughYourWindow() {}
}

あなたがはっきりと見るように、あなたが眠ろうとするとき、多くの「もの」は迷惑になることができます。

インターフェースなしのクラスの使用

しかし、これらのクラスの使用に関しては問題があります。彼らには共通点はありません。各メソッドを個別に呼び出す必要があります。

class TestAnnoyingThings{
    void testAnnoyingThinks(Mosquito mosquito, Neighbour neighbour, LampJustOutsideYourWindow lamp){
         if(mosquito != null){
             mosquito.flyAroundYourHead();
         }
         if(neighbour!= null){
             neighbour.startScreaming();
         }
         if(lamp!= null){
             lamp.shineJustThroughYourWindow();
         }
    }
}

インターフェース付きモデル

この問題を克服するために、インターフェースを導入できますここに画像の説明を入力してください

interface Annoying{
   public void annoy();

}

そしてそれをクラスの中に実装する

class Mosquito implements Annoying {
    void flyAroundYourHead(){}

    void annoy(){
        flyAroundYourHead();
    }
}

class Neighbour implements Annoying{
    void startScreaming(){}

    void annoy(){
        startScreaming();
    }
}

class LampJustOutsideYourWindow implements Annoying{
    void shineJustThroughYourWindow() {}

    void annoy(){
        shineJustThroughYourWindow();
    }
}

インターフェースでの使用

これらのクラスの使用がはるかに簡単になります

class TestAnnoyingThings{
    void testAnnoyingThinks(Annoying annoying){
        annoying.annoy();
    }
}

わかりましたが、実装する必要はNeighbourありませんか?LampJustOutsideYourWindowAnnoying
スターダスト

はい、指摘していただきありがとうございます。私はこの変更を加えて編集しました
Marcin Szymczak

2

最も簡単な例は、Payment Processors(Paypal、PDSなど)のようなものです。

たとえば、ProcessACHメソッドとProcessCreditCardメソッドを持つインターフェイスIPaymentProcessorを作成するとします。

これで、具体的なPaypal実装を実装できます。これらのメソッドでPayPal固有の関数を呼び出すようにします。

後で別のプロバイダーに切り替える必要があると判断した場合は、切り替えることができます。新しいプロバイダー用に別の具体的な実装を作成するだけです。関連付けられているのはインターフェース(契約)だけなので、それを使用するコードを変更することなく、アプリケーションが使用するものを交換できます。


2

また、モックユニットテスト(.Net)を実行することもできます。クラスがインターフェースを使用している場合は、ユニットテストでオブジェクトをモックし、ロジックを簡単にテストできます(実際にデータベースやWebサービスなどにアクセスする必要はありません)。

http://www.nmock.org/


2

.NET Frameworkアセンブリを参照し、標準オブジェクトの基本クラスにドリルダウンすると、多くのインターフェイス(ISomeNameという名前のメンバー)に気付くでしょう。

インターフェースは基本的に、大小のフレームワークを実装するためのものです。自分のフレームワークを書きたいと思うまで、インターフェースについても同じように感じました。また、インターフェースを理解することで、フレームワークをより迅速に習得できることがわかりました。何に対してもよりエレガントなソリューションを書きたいと思った瞬間、インターフェースが非常に理にかなっていることに気付くでしょう。それは、クラスに適切な服を着させる方法のようなものです。さらに重要なのは、クラスがインターフェイスを実装するときに複雑なオブジェクトの複雑さが緩和されるため、インターフェイスによってシステムの自己文書化が大幅に向上し、機能の分類に役立つことです。

クラスは、明示的または暗黙的にフレームワークに参加できるようにしたいときにインターフェースを実装します。たとえば、IDisposableは、人気のある便利なDispose()メソッドにメソッドシグネチャを提供する一般的なインターフェイスです。フレームワークでは、あなたまたは他の開発者がクラスについて知る必要があるのは、それがIDisposableを実装する場合、クリーンアップの目的で((IDisposable)myObject).Dispose()を呼び出すことができることを知っていることだけです。

古典的な例:IDisposableインターフェイスを実装しないと、パラメーターとして指定されたオブジェクトをIDisposableに暗黙的にキャストできる必要があるため、C#で「using()」キーワードコンストラクトを使用できません。

複雑な例:より複雑な例は、System.ComponentModel.Componentクラスです。このクラスは、IDisposableとIComponentの両方を実装します。すべてではありませんが、ビジュアルデザイナーが関連付けられている.NETオブジェクトのほとんどは、IDEがコンポーネントと対話できるようにIComponentを実装しています。

結論:.NET Frameworkに慣れてきたら、オブジェクトブラウザまたは.NETリフレクタ(無料)ツール(http://www.red-gate.com)内で新しいクラスに遭遇したときに最初に行うことです。 / products / reflector /)は、継承元のクラスと、それが実装するインターフェースを確認するためのものです。.NETリフレクターは、派生クラスも表示できるため、オブジェクトブラウザーよりも優れています。これにより、特定のクラスから派生するすべてのオブジェクトについて学ぶことができ、それによって、存在することを知らなかったフレームワーク機能について潜在的に学ぶことができます。これは、更新された名前空間または新しい名前空間が.NET Frameworkに追加された場合に特に重要です。


2

あなたが一人称シューティングゲームを作っていると考えてください。プレイヤーは選択可能な複数の銃を持っています。

Gun関数を定義するインターフェースを持つことができますshoot()

GunつまりShotGun Sniper、クラスのさまざまなサブクラスが必要です。

ShotGun implements Gun{
    public void shoot(){
       \\shotgun implementation of shoot.
    } 
}

Sniper implements Gun{
    public void shoot(){
       \\sniper implementation of shoot.
    } 
}

シュータークラス

射手は彼の鎧にすべての銃を持っています。Listそれを表すを作成してみましょう。

List<Gun> listOfGuns = new ArrayList<Gun>();

射手は必要に応じて、関数を使用して彼の銃を循環します switchGun()

public void switchGun(){
    //code to cycle through the guns from the list of guns.
    currentGun = //the next gun in the list.
}

上記の関数を使用して現在のGunを設定し、が呼び出されたshoot()ときに関数を呼び出すだけ fire()です。

public void fire(){
    currentGun.shoot();
}

シュート機能の動作は、Gunインターフェースの実装によって異なります。

結論

実装されたクラスのインスタンス(オブジェクト)に基づいて、クラス関数が別のクラスの関数に依存しその動作が変更される場合に、インターフェイスを作成します。

たとえばfire()Shooterクラスの関数は、guns(SniperShotGun)がshoot()関数を実装することを期待しています。だから私たちが銃を切り替えて発砲した場合。

shooter.switchGun();
shooter.fire();

fire()関数の動作を変更しました。


1

ラーセナルの発言を拡大する。インターフェイスは、すべての実装クラスが従わなければならないコントラクトです。このため、コントラクトに対してプログラミングと呼ばれる手法を使用できます。これにより、ソフトウェアを実装に依存しないようにすることができます。


1

インターフェイスは通常、オブジェクトが示すことができる動作を定義する場合に使用されます。

.NETの世界におけるこの良い例は、IDisposableインターフェイスです。これは、手動で解放する必要があるシステムリソースを使用するすべてのMicrosoftクラスで使用されます。それを実装するクラスにはDispose()メソッドが必要です。

(Dispose()メソッドは、VB.NETおよびC#の使用言語コンストラクトからも呼び出され、IDisposables でのみ機能します)

TypeOf ... Is(VB.NET)、is(C#)、instanceof(Java)などの構造を使用して、オブジェクトが特定のインターフェースを実装しているかどうかを確認できることに注意してください。


1

複数の人がすでに回答している可能性があるため、インターフェースを使用して、クラス間の動作を同じ方法で実装しない特定の動作を強制できます。したがって、インターフェイスを実装することで、クラスにインターフェイスの動作があることを示しています。Dog、Cat、Birdなどのクラスは動物のタイプであるため、IAnimalインターフェイスは一般的なインターフェイスではありません。継承の場合は、おそらく拡張する必要があります。代わりに、この場合、インターフェースはIRunnable、IFlyable、ITrainableなどの動物の行動に似ています。

インターフェースは多くのものに適しています。重要なことの1つはプラグイン可能性です。たとえば、Listパラメーターを持つメソッドを宣言すると、Listインターフェースを実装するすべてのものが渡されるため、開発者は大量のコードを書き直す必要なく、後で別のリストを削除してプラグインできます。

インターフェースを決して使用しない可能性もありますが、プロジェクトを最初から設計する場合、特にある種のフレームワークの場合は、おそらくそれらに慣れる必要があります。

Coad、Mayfield、およびKernによるJavaデザインのインターフェースに関する章を読むことをお勧めします。彼らはそれを平均的な紹介文より少し良く説明しています。Javaを使用しない場合は、この章の冒頭を読むだけで十分です。これは主に概念です。


1

システムに柔軟性を追加するプログラミング技術と同様に、インターフェイスもある程度の複雑さを追加します。それらは多くの場合素晴らしいものであり、どこでも使用できます(すべてのクラスのインターフェイスを作成できます)。

ここにはいつものようにトレードオフがあります:保守性よりも柔軟性です。どちらがより重要ですか?答えはありません-それはプロジェクトに依存します。ただし、すべてのソフトウェアを保守する必要があることを覚えておいてください...

だから私のアドバイス:本当に必要になるまでインターフェースを使わないでください。(Visual Studioを使用すると、既存のクラスから2秒でインターフェイスを抽出できます。急いではいけません。)

そうは言っても、いつインターフェースを作成する必要がありますか?

突然メソッドをリファクタリングするときにそれを行います2つ以上の類似したクラス処理する必要がます。次に、インターフェイスを作成し、このインターフェイスを2つ(またはそれ以上)の類似したクラスに割り当て、メソッドのパラメータータイプを変更します(クラスタイプをインターフェイスタイプに置き換えます)。

そしてそれは動作します:o)

1つの例外:オブジェクトをモックする場合、インターフェイスの方がはるかに使いやすくなります。そのため、私はこのためのインターフェースを作成することがよくあります。

PS:「インターフェース」と書いたときの意味は、「すべての基本クラスのインターフェース」で、純粋なインターフェースクラスも含まれます。抽象クラスはロジックを追加できるため、純粋なインターフェースよりも優れている場合が多いことに注意してください。

よろしく、シルヴァン。


1

ライブラリ開発者(他のコーダー用にコーディングする人)になると、インターフェースが明らかになります。私たちのほとんどは、既存のAPIとプログラミングライブラリを使用するアプリケーション開発者として始まります。

インターフェイスがコントラクトであるのと同じように、インターフェイスはコードの一部を安定させるための優れた方法であると誰も述べていません。これは、チームプロジェクトの場合(または他の開発者が使用するコードを開発する場合)に特に役立ちます。だから、ここにあなたのための具体的なシナリオがあります:

チームでコードを開発しているとき、他の人があなたが書いたコードを使用している可能性があります。彼らはあなたの(安定した)インターフェースにコーディングするときに最も幸せになりますし、チームのコードを壊すことなく(インターフェースの後ろに隠されている)実装を自由に変更できるときは幸せになります。これは情報非表示のバリアントです(インターフェースはパブリックであり、実装はクライアントプログラマーから隠されています)。保護されたバリエーションの詳細をご覧ください。

インターフェイスへのコーディングに関するこの関連質問も参照してください。


1

インターフェースを使用する目的はたくさんあります。

  1. ポリモーフィックな動作で使用します。子クラスへの参照を持つインターフェースを持つ子クラスの特定のメソッドを呼び出す場所。

  2. 最も一般的な使用法のように、必要なすべてのメソッドを実装するためのクラスとのコントラクトを持つことは、COMオブジェクトの場合であり、インターフェイスを継承するDLLでラッパークラスが生成されます。これらのメソッドはバックグラウンドで呼び出され、実装する必要があるだけですが、COM DLLで定義されているのと同じ構造であり、COM DLLで公開されているインターフェースを通じてのみ知ることができます。

  3. クラスの特定のメソッドをロードすることにより、メモリ使用量を削減します。3つのビジネスオブジェクトがあり、それらが単一のクラスに実装されている場合と同様に、3つのインターフェイスを使用できます。

例:IUser、IOrder、IOrderItem

public interface IUser()
{

void AddUser(string name ,string fname);

}

// Same for IOrder and IOrderItem
//


public class  BusinessLayer: IUser, IOrder, IOrderItem

{    
    public void AddUser(string name ,string fname)
    {
        // Do stuffs here.
    }

    // All methods from all interfaces must be implemented.

}

ユーザーのみを追加する場合は、次のようにします。

IUser user = new (IUser)BusinessLayer();

// It will load  all methods into memory which are declared in the IUser interface.

user.AddUser();
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.