language-agnostic - 設計 - 命名規則 英語




「インターフェイスにプログラムする」とはどういう意味ですか? (20)

私はこれが数回言及しているのを見て、それが何を意味するのかはっきりしていない。 あなたはいつ、なぜこれをやるのですか?

私はインターフェイスが何をしているのか知っていますが、これで私が明らかにしていないという事実は、それらを正しく使用することができなくなっていると思います。

あなたがしなければならないのはそうですか?

IInterface classRef = new ObjectWhatever()

あなたはIInterfaceを実装するクラスを使用できますか? いつあなたはそれをする必要がありますか? 私が考えることができるのは、メソッドを持っていて、どのオブジェクトがIInterface実装するのに期待されているかわからない場合です。 どのくらいの頻度でそれを行う必要があるかは考えられません...(また、インターフェイスを実装するオブジェクトを取り込むメソッドを記述することもできますか?

申し訳ありませんが、私は完全にポイントを逃した。


Q: - ... "インターフェイスを実装するクラスを使用できますか?"
A:はい。

Q:「いつあなたはそれをする必要がありますか?」
A: - インタフェースを実装するクラスが必要なたびに。

注意: 私たちはクラスによって実装されていないインタフェースをインスタンス化できなかった - 真。

  • どうして?
  • インタフェースにはプロトタイプのみがあり、定義はありません(関数名であり、ロジックではありません)

AnIntf​​ anInst =新しいAclass();
// AclassがAnIntf​​を実装している場合にのみこれを行うことができます。
// anInstはAclass参照を持ちます。

注意:
BclassとCclassが同じDintfを実装すると、何が起こったのか理解できるようになりました。

Dintf bInst = new Bclass();  
// now we could call all Dintf functions implemented (defined) in Bclass.

Dintf cInst = new Cclass();  
// now we could call all Dintf functions implemented (defined) in Cclass.

私たちが持っているもの:
同じインタフェースプロトタイプ(インタフェース内の関数名)。異なる実装を呼び出す。

参考文献:
プロトタイプ - ウィキペディア


Inversion of Controlを調べる必要があります。

このようなシナリオでは、あなたはこれを書かないでしょう:

IInterface classRef = new ObjectWhatever();

あなたは次のようなものを書くでしょう:

IInterface classRef = container.Resolve<IInterface>();

これは、 containerオブジェクトのルールベースの設定に入り、実際のオブジェクトを構築します。これはObjectWhateverでもかまいません。 重要なことは、このルールを別のタイプのオブジェクトを使用したものに置き換えることができ、コードが引き続き機能することです。

テーブルからIoCを離しておくと、オブジェクトの種類やオブジェクトの種類を特定できないオブジェクトに対話できることを知っているコードを書くことができます。

これはパラメータを渡すときに便利です。

カッコで囲まれた質問については、「インターフェイスを実装するオブジェクトを取り込む方法は?それは可能でしょうか?」とC#では、単にパラメータ型のインターフェイスタイプを使用します。

public void DoSomethingToAnObject(IInterface whatever) { ... }

これは "特定のことをするオブジェクトとの会話"につながります。 上記で定義したメソッドは、オブジェクトから何を期待するのか、IInterfaceのすべてを実装するのかを知っていますが、どのタイプのオブジェクトであろうと、それが契約に従っていることだけです。

たとえば、おそらく計算機に精通していて、たぶんあなたの日にかなりの数を使用しているかもしれませんが、ほとんどの場合、それらはすべて異なっています。 一方で、標準的な電卓がどのように機能すべきかを知っているので、各電卓が持っていない特定の機能を使用できない場合でも、それらをすべて使用することができます。

これはインターフェイスの美しさです。 特定の動作を期待できるオブジェクトが渡されることがわかっているコードを書くことができます。 それは、それがどんな種類のオブジェクトであっても、それが必要な振る舞いをサポートしているということだけを気にしません。

具体的な例を教えてください。

私たちには、Windowsフォーム用のカスタムビルド翻訳システムがあります。 このシステムはフォームのコントロールをループし、それぞれのテキストを翻訳します。 システムは、コントロールタイプのコントロールのような基本的なコントロールや、同様の基本的なものを処理する方法を知っていますが、基本的なものについては、それは不足しています。

コントロールは制御できない事前定義されたクラスから継承されるので、次の3つのうちのどれかを実行できます:

  1. 翻訳システムのサポートを構築して、どのタイプのコントロールを使用しているのかを具体的に検出し、正しいビット(メンテナンスの悪夢)を翻訳します。
  2. 基底クラスへのサポートを構築する(すべてのコントロールが異なる事前定義クラスから継承するため不可能)
  3. インターフェイスのサポートを追加する

だから我々はnrをやった。 3.私たちのすべてのコントロールは、ILocalizableを実装しています。これは、 "自分"を翻訳テキスト/ルールのコンテナに翻訳する1つの方法を提供するインターフェイスです。 したがって、フォームは、特定のインターフェイスを実装し、コントロールをローカライズするために呼び出すことができるメソッドがあることがわかっているだけで、見つかったコントロールの種類を知る必要はありません。


インタフェースへのコード実装はJavaやInterfaceの構造とは何の関係もありません。

このコンセプトは、Patterns / Gang of Fourの著書に浮かびましたが、おそらくその前のほうが多分でした。 この概念は、Javaが存在する前から確かに存在していました。

Java Interfaceのコンストラクトはこのアイデアを助けるために作成されたものであり、人々は元の意図よりも意味の中心として構造に集中しすぎてしまっています。 しかし、それがJava、C ++、C#などで公開メソッドと非公開メソッドと属性を持つ理由です。

これは、オブジェクトまたはシステムのパブリックインターフェイスとやりとりすることを意味します。 それが内部的に何をするのかを心配したり、予想したりしないでください。 それがどのように実装されるか心配しないでください。 オブジェクト指向のコードでは、私たちはpublicメソッドとprivateメソッド/属性を持っています。 プライベートメソッドはクラス内でのみ使用できるため、パブリックメソッドを使用することを意図しています。 それらはクラスの実装を構成し、パブリック・インタフェースを変更することなく、必要に応じて変更できます。 機能性に関しては、クラスのメソッドは、同じパラメーターを使用して呼び出すたびに、同じ結果が期待される同じ操作を実行します。 これにより、作成者は、クラスがどのように動作し、その実装が変更されるのか、人々がそのクラスとどのように対話するかを変更することができます。

また、Interfaceのコンストラクトを使用することなく、インプリメンテーションではなくインターフェイスにプログラミングすることができます。 Interfaceには、C ++での実装ではなく、Interfaceの構造体を持たないプログラミングができます。 2つの大規模なエンタープライズシステムは、システム内部のオブジェクトのメソッドを呼び出すのではなく、パブリックインターフェイス(コントラクト)を介して相互作用する限り、はるかに堅牢に統合できます。 インターフェイスは、同じ入力パラメータを与えられた場合、常に同じ期待された方法で反応することが期待されます。 実装ではなくインタフェースに実装されている場合 このコンセプトは多くの場所で機能します。

Javaインターフェイスには、「実装ではなくインターフェイスへのプログラム」の概念とは何かがあるとの考えを揺さぶってください。 彼らは概念を適用するのを助けることができますが、概念ではありません


インタフェースへのプログラムは、インタフェースによって定義された契約の実装をシームレスに変更することができます。これは、契約と特定の実装間の緩やかな結合を可能にします。

IInterface classRef = new ObjectWhatever()

あなたはIInterfaceを実装するクラスを使用できますか?いつあなたはそれをする必要がありますか?

このSEの質問を良い例として見てみましょう。

なぜJavaクラスのインタフェースが優先されるべきですか?

インターフェイスヒットパフォーマンスを使用していますか?

もしそうならどれくらい?

はい。サブ秒で若干のパフォーマンスオーバーヘッドが発生します。しかし、アプリケーションにインターフェースの実装を動的に変更する必要がある場合は、パフォーマンスへの影響を心配しないでください。

2ビットのコードを維持することなく、どうやってそれを避けることができますか?

アプリケーションで必要な場合は、複数のインタフェース実装を避けてください。特定の実装とのインターフェイスの緊密な結合がない場合は、ある実装を他の実装に変更するためにパッチを展開する必要があります。

1つの良いユースケース:戦略パターンの実装:

戦略パターンの実例


C ++の説明。

クラスをパブリックメソッドとみなしてください。

次に、独自の関数を実行するために、これらのパブリックメソッドに「依存する」テンプレートを作成することができます(クラスのパブリックインターフェイスで定義された関数呼び出しを行います)。このテンプレートはVectorクラスのようなコンテナであり、それが依存するインターフェースは検索アルゴリズムです。

関数/インタフェースVectorを定義するアルゴリズムクラスはすべて、(契約書の元の返答で説明されているように) '契約'を満たすものです。アルゴリズムは同じ基本クラスである必要はありません。唯一の要件は、Vectorが依存する関数/メソッド(インタフェース)がアルゴリズムで定義されていることです。

このすべてのポイントは、Vectorが依存するインターフェース(バブル検索、シーケンシャル検索、クイック検索)を提供している限り、異なる検索アルゴリズム/クラスを提供できることです。

また、検索アルゴリズムが依存するインタフェース/コントラクトを満たすことによって、Vectorと同じ検索アルゴリズムを使用する他のコンテナ(リスト、キュー)を設計することもできます。

これは、あなたが過度に成長した継承ツリーで問題を複雑にすることなく、あなたが作成するすべての新しいオブジェクトに特有の繰り返しアルゴリズムではなく、一度アルゴリズムを書くことができるので、時間を節約します(OOP原則のコード再利用)。

物事がどのように作用するかについての「欠落」については、これは標準のTEMPLATEライブラリのフレームワークのほとんどがどのように動作しているかのように(少なくともC ++では)大きな時間を費やしています。

もちろん、継承クラスと抽象クラスを使用する場合は、インタフェースへのプログラミング方法が変わります。しかし原理は同じです、あなたの公開関数/メソッドはあなたのクラスインタフェースです。

これは大きなテーマであり、デザインパターンの基本原則の1つです。


Javaでは、これらの具体的なクラスはすべてCharSequenceインタフェースを実装しています。

CharBuffer、String、StringBuffer、StringBuilder

これらの具体的なクラスには、Object以外の共通の親クラスはありません。したがって、それぞれが文字の配列、そのような表現、またはそのような操作を行うこと以外は何も関係ありません。たとえば、Stringオブジェクトのインスタンス化後はStringの文字を変更することはできませんが、StringBufferまたはStringBuilderの文字は編集できます。

これらのクラスのそれぞれは、CharSequenceインタフェースメソッドを適切に実装することができます。

char charAt(int index)
int length()
CharSequence subSequence(int start, int end)
String toString()

場合によっては、Stringを受け入れるために使用されたJavaクラスライブラリクラスが、CharSequenceインタフェースを受け入れるように改訂されました。したがって、StringBuilderのインスタンスがある場合、Stringオブジェクト(新しいオブジェクトインスタンスをインスタンス化することを意味します)を抽出する代わりに、StringBuilder自体をCharSequenceインターフェイスを実装するように渡すことができます。

いくつかのクラスが実装するAppendableインタフェースは、基礎となる具象クラスオブジェクトインスタンスのインスタンスに文字を追加できるあらゆる状況で、同じ種類の利点を持っています。これらの具体的なクラスはすべて、Appendableインターフェイスを実装しています。

バッファリングされたWriter、CharArrayWriter、CharBuffer、FileWriter、FilterWriter、LogStream、OutputStreamWriter、PipedWriter、PrintStream、PrintWriter、StringBuffer、StringBuilder、StringWriter、Writer


これにより、類似したクラスのセットを持つときに、コードの拡張性が向上し、保守が容易になります。 私はジュニアプログラマですので、私は専門家ではありませんが、私はちょうど同様のものを必要とするプロジェクトを終了しました。

私は、医療機器を稼働しているサーバと通信するクライアント側のソフトウェアを扱っています。 私たちは、このデバイスの新しいバージョンを開発しています。このバージョンには、顧客が時々設定しなければならない新しいコンポーネントがいくつかあります。 新しいコンポーネントには2つのタイプがあり、それらは異なっていますが、それらも非常に似ています。 基本的には、私は2つの設定フォームを作成しなければなりませんでした。

私は、実際のロジックのほぼすべてを保持するコントロールタイプごとに抽象基本クラスを作成し、次に、2つのコンポーネントの違いを処理するために派生したタイプを作成することをお勧めします。 しかし、基底クラスは、常に型について心配しなければならない場合、これらのコンポーネントに対して操作を実行することはできませんでした(もちろん、それらは持つことができますが、すべてのメソッドに "if"ステートメントまたはスイッチがあります) 。

私はこれらのコンポーネントのための単純なインターフェイスを定義し、すべての基本クラスはこのインターフェイスと話します。 今私が何かを変更すると、どこでもうまく動作し、コードの重複はありません。


そこにはたくさんの説明がありますが、それはもっと簡単になります。 たとえばList取る。 次のようにリストを実装できます。

  1. 内部配列
  2. リンクされたリスト
  3. その他の実装

インタフェースを構築することで、 List挙げることができます。 あなたは、リストの定義や実際にList意味するものについてのみコーディングします。

任意のタイプの実装を使用して、内部的にarray実装を行うことができます。 しかし、何らかの理由でバグやパフォーマンスなどの実装を変更したいとします。 次に、 List<String> ls = new ArrayList<String>()宣言をList<String> ls = new LinkedList<String>()ます。

コード内のどこに他のものを変更する必要がありますか? 他のすべてはList定義に基づいて構築されているからです。


また、私はここで多くの良い説明的な答えを見ているので、私はこの方法を使用するときに気づいたいくつかの追加情報を含め、ここで私の見解を示したいと思います。

単体テスト

過去2年間、私は趣味のプロジェクトを書いており、私はそれのための単体テストを書かなかった。約50K行を書くと、単体テストを書くことが本当に必要であることがわかった。私はインターフェイスを使用しませんでした(または非常に控えめに)...私は最初の単体テストをしたとき、私はそれが複雑であることがわかりました。どうして?

クラスインスタンスをたくさん作成しなければならなかったので、クラス変数やパラメータとして入力に使用されました。したがって、テストは統合テストのようになります(すべてが一緒になっているので、クラスの完全なフレームワークを作る必要があります)。

インターフェースの恐れはインターフェースを使うことに決めました。私の懸念は、(すべての使用されたクラスで)どこでもすべての機能を複数回実装しなければならないということでした。何らかの形でこれは本当ですが、継承を使用することによって多くのことを減らすことができます。

インターフェイスと継承の組み合わせ私は、組み合わせを見つけ出して使用するのが非常に良いです。私は非常に簡単な例を示します。

public interface IPricable
{
    int Price { get; }
}

public interface ICar : IPricable

public abstract class Article
{
    public int Price { get { return ... } }
}

public class Car : Article, ICar
{
    // Price does not need to be defined here
}

このようにしてコードをコピーする必要はなく、カーをインタフェース(ICar)として使用する利点があります。


インタフェースは契約のようなもので、契約クラス(インタフェース)で書かれたメソッドを実装するクラスです。javaは多重継承を提供しないので、インタフェースへのプログラミングは複数の継承の目的を達成する良い方法です。すでに他のクラスBを拡張していますが、そのクラスAが特定のガイドラインに従うか、または特定の契約を実装し、インターフェイス戦略をプログラミングすることによってそうすることもできます。


インターフェイスの仕組みを理解しているように思えますが、いつインターフェイスを使うのか、どんな利点があるのか​​は不明です。 インターフェイスが意味をなされる場合のいくつかの例を以下に示します。

// if I want to add search capabilities to my application and support multiple search
// engines such as google, yahoo, live, etc.

interface ISearchProvider
{
    string Search(string keywords);
}

GoogleSearchProvider、YahooSearchProvider、LiveSearchProviderなどを作成できます

// if I want to support multiple downloads using different protocols
// HTTP, HTTPS, FTP, FTPS, etc.
interface IUrlDownload
{
    void Download(string url)
}

// how about an image loader for different kinds of images JPG, GIF, PNG, etc.
interface IImageLoader
{
    Bitmap LoadImage(string filename)
}

JpegImageLoader、GifImageLoader、PngImageLoaderなどを作成します。

ほとんどのアドインとプラグインシステムは、インターフェイスを無効にします。

別の一般的な使用方法は、リポジトリパターンです。 さまざまなソースから郵便番号のリストをロードしたいとします

interface IZipCodeRepository
{
    IList<ZipCode> GetZipCodes(string state);
}

私はXMLZipCodeRepository、SQLZipCodeRepository、CSVZipCodeRepositoryなどを作成することができました。私のWebアプリケーションでは、初期段階でXMLリポジトリを作成することが多いので、SQLデータベースを準備する前に何かを稼働させることができます。 データベースが準備できたら、XMLバージョンを置き換えるSQLRepositoryを作成します。 私のコードの残りの部分は、インターフェイスから離れているので変更されません。

メソッドは次のようなインタフェースを受け入れることができます:

PrintZipCodes(IZipCodeRepository zipCodeRepository, string state)
{
    foreach (ZipCode zipCode in zipCodeRepository.GetZipCodes(state))
    {
        Console.WriteLine(zipCode.ToString());
    }
}

インターフェイスへのプログラミングは、「私はこの機能が必要で、どこから来ても気にしません」と言っています。

(Javaでは) ListインタフェースとArrayListクラス、 LinkedListコンクリートクラスを考えてみましょう。 私が気にするのは、繰り返しを介してアクセスする必要がある複数のデータ項目を含むデータ構造を持っているということです。 List選択するとしたら99%の時間です。 リストのどちらかの端から一定時間の挿入/削除が必要なことが分かっている場合は、 LinkedList具体的な実装を選択するか、 Queueインターフェイスを使用する可能性があります。 インデックスでランダムアクセスが必要なことがわかったら、 ArrayListコンクリートクラスを選択します。


インターフェイスを使用することは、クラス間の不要な結合を削除するだけでなく、コードを簡単にテストできるようにするための重要な要素です。 クラスの操作を定義するインタフェースを作成することにより、その機能を使用するクラスに、実装クラスに直接依存することなくクラスを使用できるようになります。 後で異なるインプリメンテーションを変更して使用する場合は、インプリメンテーションがインスタンス化されるコードの部分だけを変更する必要があります。 コードの残りの部分は、実装クラスではなくインターフェイスに依存するため、変更する必要はありません。

これはユニットテストの作成に非常に役立ちます。 テストするクラスでは、インターフェースに依存し、クラスのインスタンス(または必要に応じてインターフェースのインスタンスを作成できるファクトリー)をコンストラクターまたはプロパティー・セットターを介して注入します。 クラスは、提供された(または作成された)インターフェイスをメソッドで使用します。 テストを書くときは、インターフェイスを模擬したり、偽装したり、単体テストで設定されたデータで応答するインターフェイスを提供したりすることができます。 これは、テスト対象のクラスが具体的な実装ではなくインターフェイスのみを扱うためです。 あなたのモックや偽のクラスを含むインターフェースを実装しているクラスがあれば、それを行います。

EDIT:以下は、Erich Gammaが引用した「プログラミングではなく、インターフェイスに実装する」という記事へのリンクです。

http://www.artima.com/lejava/articles/designprinciples.html


ショート・ストーリー:郵便配達員は家に帰って、届くように書かれた住所を含むカバー(手紙、書類、小切手、ギフトカード、申請書、ラブレター)を受け取るよう求められます。

カバーがなく、郵便配達人に家に帰ってすべてのものを受け取り、郵便配達人が混乱を招く可能性があることを他の人に伝えるよう依頼すると、

だから、より良いラップ(それは私たちの話ではインターフェイスです)彼は彼の仕事をうまくやるでしょう。

今、郵便配達の仕事は、カバーを受け取って配送することだけです。(彼はカバーの中に何が入っているのか気にしません)。

interface実際の型ではなく型を作成しますが、実際の型で実装します。

インターフェイスへの作成は、コンポーネントが他のコードに簡単にフィットすることを意味します。

私はあなたに例を挙げます。

以下のようなAirPlaneインターフェースがあります。

interface Airplane{
    parkPlane();
    servicePlane();
}

例えば、あなたのControllerクラスの中にPlanesのようなメソッドがあるとします

parkPlane(Airplane plane)

そして

servicePlane(Airplane plane)

あなたのプログラムに実装されています。あなたのコードをBREAKしません。つまり、引数を受け入れる限り変更する必要はありませんAirPlane

それは、実際のタイプのにもかかわらず、任意の飛行機を受け入れますのでflyerhighflyrfighter、など

また、コレクションでは:

List<Airplane> plane; //すべての飛行機を利用します。

次の例は、あなたの理解を明確にします。

あなたはそれを実装する戦闘機を持っているので

public class Fighter implements Airplane {

    public void  parkPlane(){
        // Specific implementations for fighter plane to park
    }
    public void  servicePlane(){
        // Specific implementatoins for fighter plane to service.
    }
}

HighFlyerと他のclasessの場合と同じこと:

public class HighFlyer implements Airplane {

    public void  parkPlane(){
        // Specific implementations for HighFlyer plane to park
    }

    public void  servicePlane(){
        // specific implementatoins for HighFlyer plane to service.
    }
}

今度はあなたのコントローラーのクラスをAirPlane何回か考えてみてください。

あなたのControllerクラスが以下のようなControlPlaneであると仮定し、

public Class ControlPlane{ 
 AirPlane plane;
 // so much method with AirPlane reference are used here...
}

ここで魔法は

新しいAirPlaneタイプのインスタンスを必要な数だけ作成し、変更することはできません

ControlPlaneクラスのコード。

インスタンスを追加することができます..

JumboJetPlane // implementing AirPlane interface.
AirBus        // implementing AirPlane interface.

以前に作成した型のインスタンスも削除することができます。


プログラムへのインターフェイスは、あなたのコードが前の機能を中断することなく拡張されるべきであることを意味します。


ユニットテストにも適しています。独自のクラス(インタフェースの要件を満たすクラス)をそれに依存するクラスに注入できます


既に選択されている回答(およびここでのさまざまな有益な投稿)に加えて、私はヘッドファーストデザインパターンのコピーを取得することを強くお勧めします。 非常に読みやすいので、あなたの質問に直接答え、重要な理由を説明し、その原則(および他のもの)を利用するために使用できる多くのプログラミングパターンを示します。


既存の投稿に追加する場合、開発者が別々のコンポーネントを同時に操作しているときに、インターフェイスにコード化することで大規模なプロジェクトに役立つことがあります。 必要なのは、インターフェースを前もって定義し、それらにコードを書き込むだけです。他の開発者が実装しているインターフェースにコードを書き込むだけです。


私が学生に与える具体的な例は、

List myList = new ArrayList(); // programming to the List interface

の代わりに

ArrayList myList = new ArrayList(); // this is bad

これらは短いプログラムではまったく同じように見えますが、プログラムでmyList 100回使用すると、違いを見ることができます。 最初の宣言では、 Listインターフェイスで定義されているmyListメソッドのみを呼び出すことができます( ArrayList固有のメソッドはありません)。 このようにインターフェイスにプログラミングしたことがある場合は、後で必要なものを決定することができます

List myList = new TreeList();

その1つの場所でコードを変更するだけです。 インターフェイスにプログラミングしたために実装を変更することによって、コードの残りの部分が壊れることはありません。

メリットは、メソッドのパラメータと戻り値について話しているときには、はるかに明白です(私は思います)。 たとえばこれを取る:

public ArrayList doSomething(HashMap map);

そのメソッド宣言は、2つの具体的な実装( ArrayListHashMap )につながります。 そのメソッドが他のコードから呼び出されるとすぐに、それらの型を変更すると、おそらく呼び出しコードも変更する必要があります。 インターフェイスにプログラミングするほうがよいでしょう。

public List doSomething(Map map);

現在、どのようなListを返すか、どのMapパラメータとして渡すかは関係ありません。 doSomethingメソッド内で行った変更によって、呼び出しコードを変更する必要はありません。


私はこの質問に遅れていますが、ここでは、「実装ではなくインターフェイスへのプログラム」という行が、GoF(Gang of Four)Design Patternsの本でよく議論されていることをここでお伝えしたいと思います。

それは、p。 18:

インプリメンテーションではなくインターフェイスへのプログラム

変数を特定の具象クラスのインスタンスに宣言しないでください。 代わりに、抽象クラスによって定義されたインタフェースにのみコミットします。 これは、この本のデザインパターンの共通のテーマであることがわかります。

それ以上では、それは以下から始まりました:

抽象クラスによって定義されたインタフェースの観点からのみオブジェクトを操作することには、2つの利点があります。

  1. クライアントは、オブジェクトがクライアントが期待するインターフェイスに固執する限り、使用する特定のタイプのオブジェクトを認識しません。
  2. クライアントはこれらのオブジェクトを実装するクラスを認識しません。 クライアントは、インタフェースを定義する抽象クラスについてのみ知っています。

つまり、鴨のためのquack() bark()メソッド、犬のためのbark()メソッドを持つようにクラスを記述しないでください。それらはクラス(またはサブクラス)の特定の実装にはあまりにも特殊なので、 。 代わりに、 giveSound()move()などの基本クラスで使用するのに十分な一般的な名前を使用してメソッドを記述し、アヒル、犬、さらには車に使用できるようにしてから、クラスはquack()bark()どちらを使用するか、またはオブジェクトに送信する正しいメッセージを発行する前に型を決定するかどうかについて考えるのではなく、 .giveSound()と言うことができます。





interface