質問がありましたが、ここで回答を確認したかったのです。
Q:インターフェイスを実装するよりも抽象クラスを拡張する方が適切なシナリオはどれですか?
A:テンプレートメソッドデザインパターンを使用している場合。
私は正しいですか?
質問を明確に述べることができなかった場合、申し訳ありません。
抽象クラスとインターフェースの基本的な違いを知っています。
1)特定の操作(メソッドを実装)のすべてのサブクラスに同じ機能を実装し、他の操作(メソッドシグネチャのみ)に異なる機能を実装する必要があるような要件の場合は、抽象クラスを使用します
2)インターフェースの実装に準拠できるように、署名を同じ(および実装が異なる)にする必要がある場合は、インターフェースを使用します
3)最大1つの抽象クラスを拡張できますが、複数のインターフェイスを実装できます
質問を繰り返します:抽象クラスを使用する必要のある上記のシナリオ以外に他のシナリオはありますか?
インターフェイスと抽象クラス
これら2つのどちらを選択するかは、実際に何をしたいかによって異なりますが、幸運なことに、Erich Gammaは少し助けてくれます。
常にトレードオフがありますが、インターフェイスは基本クラスに関して自由度を与え、抽象クラスは新しいメソッドを後で追加する自由を与えます。 –エーリッヒガンマ
他の多くのことを変更せずにインターフェイスを変更することはできませんしたがって、これを回避する唯一の方法は、まったく新しいインターフェイスを作成することです良いこと。
Abstract classes
は、主に密接に関連するオブジェクトに使用する必要があります。 Interfaces
は、無関係なクラスに共通の機能を提供するのに優れています。
インターフェイスを使用する場合
インターフェイスを使用すると、誰かが最初からインターフェイスを実装したり、元のまたは主な目的がインターフェイスとはまったく異なる他のコードでインターフェイスを実装したりできます。彼らにとって、インターフェースは偶発的なものであり、パッケージを使用できるようにするためにコードに追加する必要があるものです。欠点は、インターフェイスのすべてのメソッドがパブリックでなければならないことです。すべてを公開したくないかもしれません。
抽象クラスを使用する場合
対照的に、抽象クラスはより多くの構造を提供します。通常、いくつかのデフォルトの実装を定義し、完全な実装に役立つツールを提供します。キャッチは、それを使用するコードは、クラスをベースとして使用する必要があるということです。あなたのパッケージを使用したい他のプログラマーが既に独自にクラス階層を開発している場合、それは非常に不便かもしれません。 Javaでは、クラスは1つの基本クラスからのみ継承できます。
両方を使用する場合
インターフェイスと抽象クラスの両方の長所を提供できます。実装者は、選択した抽象クラスを無視できます。これを行うことの唯一の欠点は、インターフェース名を介してメソッドを呼び出すことです。抽象クラス名を介してメソッドを呼び出すよりもわずかに遅くなります。
質問を繰り返します:上記以外にも、特に抽象クラスを使用する必要のあるシナリオがあります(テンプレートメソッドの設計パターンは、これだけに概念的に基づいています)
はい、JAXBを使用する場合。インターフェースが好きではありません。抽象クラスを使用するか、ジェネリックでこの制限を回避する必要があります。
個人的なブログから post :
インターフェース:
一般に、インターフェースを使用して契約を定義する必要があります(達成方法ではなく、達成方法)
抽象クラス:
(部分)実装には抽象クラスを使用する必要があります。 APIコントラクトの実装方法を制限する手段になる可能性があります。
インターフェイスは、すべてのクラスが同じ構造を持っているが、機能がまったく異なるシナリオがある場合に使用されます。
抽象クラスは、すべてのクラスが同じ構造であるが、同じ機能と異なる機能を持つシナリオがある場合に使用されます。
記事をご覧ください: http://shoaibmk.blogspot.com/2011/09/abstract-class-is-class-which-cannot-be.html
抽象クラスとインターフェースのどちらを使用すべきですか?
これらのステートメントのいずれかがシナリオに該当する場合は、抽象クラスの使用を検討してください:
いくつかの密接に関連するクラス間でコードを共有したい。
抽象クラスを拡張するクラスには、多くの一般的なメソッドまたはフィールドがあるか、またはpublic(protectedやprivateなど)以外のアクセス修飾子が必要であることが予想されます。
非静的または非最終フィールドを宣言します。これにより、それらが属するオブジェクトの状態にアクセスして変更できるメソッドを定義できます。
これらのステートメントのいずれかが状況に該当する場合は、インターフェースの使用を検討してください:
無関係なクラスがインターフェイスを実装することを期待します。たとえば、インターフェイスComparableおよびCloneableは、多くの無関係なクラスによって実装されます。
特定のデータ型の動作を指定したいが、その動作を誰が実装するかは気にしません。
型の多重継承を利用したい場合。
http://docs.Oracle.com/javase/tutorial/Java/IandI/abstract.html
過去3年間で、Java 8リリースとのインターフェイスに新しい機能が追加されたことにより、状況は大きく変わりました。
Oracleのドキュメントから ページ インターフェース:
インターフェイスは、クラスに似た参照型であり、定数、メソッドシグネチャ、デフォルトメソッド、静的メソッド、およびネストされた型のみを含むことができます。メソッド本体は、デフォルトメソッドと静的メソッドにのみ存在します。
質問で引用したように、抽象クラスはテンプレートメソッドパターンに最適です。スケルトンを作成する必要があります。ここではインターフェイスを使用できません。
インターフェイスよりも抽象クラスを好むもう1つの考慮事項:
基本クラスに実装はなく、サブクラスのみが独自の実装を定義する必要があります。サブクラスと状態を共有するため、インターフェイスではなく抽象クラスが必要です。
抽象クラスは、関連するクラス間の "is a"関係を確立し、インターフェイスは、関連しないクラス間の "has a"機能を提供します。
Java-8リリース前のJavaを含むほとんどのプログラミング言語で有効な質問の2番目の部分について
常にトレードオフがありますが、インターフェイスは基本クラスに関して自由度を与え、抽象クラスは後で新しいメソッドを追加する自由度を与えます。 –エーリッヒガンマ
コードの他の多くのものを変更することなく、インターフェイスを変更することはできません
上記の2つの考慮事項を備えたインターフェースよりも抽象クラスを優先する場合、 デフォルトメソッド がインターフェースに強力な機能を追加したため、ここで再考する必要があります。
デフォルトのメソッドを使用すると、ライブラリのインターフェイスに新しい機能を追加し、それらのインターフェイスの古いバージョン用に記述されたコードとのバイナリ互換性を確保できます。
インターフェースと抽象クラスのいずれかを選択するには、Oracleのドキュメント page を引用してください:
抽象クラスはインターフェイスに似ています。それらをインスタンス化することはできません。また、実装の有無にかかわらず宣言されたメソッドが混在する場合があります。ただし、抽象クラスを使用すると、静的で最終ではないフィールドを宣言し、パブリック、プロテクト、プライベートの具象メソッドを定義できます。
インターフェイスを使用すると、すべてのフィールドは自動的にパブリック、静的、および最終になり、宣言または定義する(デフォルトメソッドとして)すべてのメソッドはパブリックになります。さらに、抽象クラスであるかどうかにかかわらず、1つのクラスのみを拡張できますが、任意の数のインターフェイスを実装できます。
詳細については、これらの関連する質問を参照してください。
インターフェイスクラスと抽象クラスの違いをどのように説明したらよいですか?
要約すると:天びんは現在インターフェースに向かって傾いています。
上記以外に、抽象クラスを使用する必要がある具体的なシナリオはありますか(テンプレートメソッドのデザインパターンは、これだけに概念的に基づいていることがわかります)。
いくつかのデザインパターンは、テンプレートメソッドパターンとは別に(インターフェイス上で)抽象クラスを使用します。
作成パターン:
構造パターン:
行動パターン:
あなたは間違っています。多くのシナリオがあります。単一の8ワードルールに減らすことはできません。
私の意見では、基本的な違いはan interface can't contain non abstract methods while an abstract class can
です。したがって、サブクラスが共通の振る舞いを共有する場合、この動作はスーパークラスで実装され、サブクラスで継承されます。
また、「Javaのソフトウェアアーキテクチャ設計ppatterns」の本から次のことを引用しました。
"Javaプログラミング言語では、多重継承はサポートされていません。つまり、クラスは1つの単一クラスからのみ継承できます。したがって、継承は、絶対に必要な場合にのみ使用してください。共通の動作は、異なる実装クラスによって実装されるJavaインターフェースの形式で宣言する必要がありますが、インターフェースにはメソッド実装を提供できないという制限があります。これらのメソッドの一部が機能の不変部分を表し、すべてのインプリメンタークラスでまったく同じ実装を持っている場合でも、インターフェイスで宣言されたすべてのメソッドこれは、冗長なコードにつながります。そのような場合、冗長なメソッド実装を必要とせずに使用できます。」
最も簡単な答えは、uou seekの一部の機能が既に実装されている場合、extend抽象クラスです。
インターフェイスを実装する場合、すべてのメソッドを実装する必要があります。ただし、抽象クラスの場合、実装する必要があるメソッドの数は少なくなります。
テンプレートデザインパターン では、動作が定義されている必要があります。この動作は、抽象である他のメソッドに依存します。サブクラスを作成し、それらのメソッドを定義することにより、実際にメインの動作を定義します。インターフェースは何も定義せず、宣言するだけなので、基礎となる動作をインターフェースに含めることはできません。そのため、テンプレートデザインパターンには常に抽象クラスが付属しています。振る舞いのフローをそのままにしたい場合は、抽象クラスを拡張する必要がありますが、メインの振る舞いをオーバーライドしないでください。
抽象クラスは、2つの重要な側面でインターフェイスとは異なります
ここにはたくさんの素晴らしい答えがありますが、私はしばしば両方のインターフェースと抽象クラスを使用することが最良のルートであると感じます。 この不自然な例を検討してください:
あなたは投資銀行のソフトウェア開発者であり、市場に注文を出すシステムを構築する必要があります。インターフェースは、取引システムが何をするかの最も一般的なアイデアをキャプチャします。
1) Trading system places orders
2) Trading system receives acknowledgements
インターフェイスでキャプチャできますITradeSystem
public interface ITradeSystem{
public void placeOrder(IOrder order);
public void ackOrder(IOrder order);
}
これで、セールスデスクや他のビジネスラインで作業するエンジニアは、システムとinterfaceを開始して、既存のアプリに発注機能を追加できます。そして、まだ構築を開始していません!これがインターフェースの力です。
そこで、stockトレーダー向けのシステムを構築します。あなたのシステムには安価な在庫を見つける機能があり、試してみたいと非常に熱心です。 findGoodDeals()
と呼ばれるメソッドでこの動作をキャプチャしますが、市場への接続に関与する厄介なものがたくさんあることも認識しています。たとえば、SocketChannel
を開く必要があります。
public class StockTradeSystem implements ITradeSystem{
@Override
public void placeOrder(IOrder order);
getMarket().place(order);
@Override
public void ackOrder(IOrder order);
System.out.println("Order received" + order);
private void connectToMarket();
SocketChannel sock = Socket.open();
sock.bind(marketAddress);
<LOTS MORE MESSY CODE>
}
public void findGoodDeals();
deals = <apply magic wizardry>
System.out.println("The best stocks to buy are: " + deals);
}
具体的な実装には、connectToMarket()
のようなこれらの厄介なメソッドがたくさんありますが、findGoodDeals()
はトレーダーが実際に気にするすべてです。
ここで、抽象クラスの出番です。上司は、通貨トレーダーもシステムを使用したいことを通知します。通貨市場を見ると、配管は株式市場とほぼ同じであることがわかります。実際、connectToMarket()
は逐語的に再利用して外国為替市場に接続できます。ただし、findGoodDeals()
は通貨の分野では非常に異なる概念です。したがって、コードベースを海を渡る外国為替ウィズキッドに渡す前に、最初にabstract
クラスにリファクタリングし、findGoodDeals()
を実装したままにします。
public abstract class ABCTradeSystem implements ITradeSystem{
public abstract void findGoodDeals();
@Override
public void placeOrder(IOrder order);
getMarket().place(order);
@Override
public void ackOrder(IOrder order);
System.out.println("Order received" + order);
private void connectToMarket();
SocketChannel sock = Socket.open();
sock.bind(marketAddress);
<LOTS MORE MESSY CODE>
}
株式取引システムは、既に定義したようにfindGoodDeals()
を実装します。
public class StockTradeSystem extends ABCTradeSystem{
public void findGoodDeals();
deals = <apply magic wizardry>
System.out.println("The best stocks to buy are: " + deals);
}
しかし今では、FXウィズキッドは通貨にfindGoodDeals()
の実装を提供するだけでシステムを構築できます。彼女はソケット接続やインターフェースメソッドを再実装する必要はありません!
public class CurrencyTradeSystem extends ABCTradeSystem{
public void findGoodDeals();
ccys = <Genius stuff to find undervalued currencies>
System.out.println("The best FX spot rates are: " + ccys);
}
インターフェースへのプログラミングは強力ですが、同様のアプリケーションは多くの場合、ほぼ同じ方法でメソッドを再実装します。抽象クラスを使用すると、インターフェースの能力を維持しながら、繰り返しを回避できます。
注:findGreatDeals()
がインターフェイスの一部ではない理由を疑問に思うかもしれません。インターフェースは、取引システムの最も一般的なコンポーネントを定義することを忘れないでください。別のエンジニアが完全に異なる取引システムを開発する場合があります。そこでは、彼らは良い取引を見つけることを気にしません。このインターフェースは、セールスデスクがシステムにもインターフェースできることを保証するため、「お得」などのアプリケーションコンセプトにインターフェースを絡ませないことが望ましいです。
これは良い質問です。これらの2つは類似していませんが、書き換えのような同じ理由で使用できます。作成するときは、インターフェイスを使用するのが最適です。クラスに分類すると、デバッグに適しています。
これが私の理解です。これが役立つことを願っています
抽象クラス:
インターフェース:
Abstract classes should be extended when you want to some common behavior to get extended
。抽象スーパークラスには共通の動作があり、サブクラスが実装する抽象メソッド/特定の動作を定義します。
Interfaces allows you to change the implementation anytime allowing the interface to be intact
。
アブストラクトとインターフェースの使用:
1つは「Is-A-Relationship」であり、もう1つは「Has-A-Relationship」です。
デフォルトのプロパティは抽象的に設定されており、インターフェイスを介して追加のプロパティを表現できます。
例:->人間には、食べる、寝るなどのデフォルトのプロパティがありますが、水泳、遊びなど他のカリキュラムアクティビティがある場合は、Interfaceで表現できます。
抽象クラス
インターフェース