web-dev-qa-db-ja.com

抽象クラスvsインターフェースvsミックスイン

誰かが私に抽象的なクラスinterfaces、そしてmixinsの違いを説明してくれませんか?私は以前コードでそれぞれ使用しましたが、技術的な違いはわかりません。

67
Sasha Chedygov

一般に:

interfaceは、操作を指定するコントラクトですが、実装はありません。一部の言語(Java、C#)はインターフェースのサポートを組み込んでおり、他の言語では、「インターフェース」はC++の純粋な仮想クラスのような規則を記述しています。

抽象クラスは、実装なしで少なくとも1つの操作を指定するクラスです。抽象クラスは、実装の一部を提供することもできます。繰り返しになりますが、一部の言語ではクラスを抽象としてマークするためのサポートが組み込まれており、他の言語では暗黙的です。たとえば、C++では、純粋な仮想メソッドを定義するクラスは抽象です。

mixinは、サブクラスで特定の機能を簡単に実装できるように設計されたクラスですが、単独で使用するようには設計されていません。たとえば、リクエストを処理するオブジェクトのインターフェースがあるとしましょう

interface RequestHandler {
  void handleRequest(Request request);
}

おそらく、あらかじめ決められた数になるまでリクエストを蓄積し、バッファをフラッシュすることで、リクエストをバッファリングすると便利でしょう。フラッシュ動作を指定せずに、mixinを使用してバッファリング機能を実装できます。

abstract class BufferedRequestHandlerMixin implements RequestHandler {
  List<Request> buffer = new List<Request>();

  void handleRequest(Request request) {
    buffer.add(request);

    if (buffer.size == BUFFER_FLUSH_SIZE) {
        flushBuffer(buffer);
        buffer.clear();
    }
  }

  abstract void flushBuffer(List<Request> buffer);
}

このようにして、バッファリング機能を毎回書き直すことなく、ディスクにリクエストを書き込んだり、Webサービスを呼び出したりするリクエストハンドラを簡単に作成できます。これらのリクエストハンドラは、BufferedRequestHandlerMixinを拡張してflushBufferを実装するだけです。

ミックスインのもう1つの良い例は、Springのサポートクラスの1つです。 HibernateDaoSupport

21
Paul Morie

Javaへの参照と、ミックスインを提供する抽象クラスの例は誤解を招く可能性があります。まず、Javaはデフォルトで「ミックスイン」をサポートしていません。 Java用語では、抽象クラスとMixinsが混乱します。

ミックスインは、「プライマリタイプ」に加えてクラスが実装できるタイプであり、オプションの動作を提供することを示します。 Javaの用語で言えば、1つの例は、Serializableを実装するビジネスバリューオブジェクトです。

Josh Bloch氏は次のように述べています。「抽象クラスはミックスインの定義に使用できません-クラスは複数の親を持つことができないため」(覚えているJavaは「拡張」候補を1つしか許可しない)

ScalaやRubyなどの言語を探して、「mixin」の概念を適切に実装してください。

6
ranj

基本的に抽象クラスは、いくつかの具体的な実装を持つインターフェースです。インターフェースは、実装の詳細を持たない単なるコントラクトです。

抽象クラスを実装するすべてのオブジェクト間で共通の機能を作成する場合は、抽象クラスを使用します。 OOPのDRY(Do n't Repeat Yourself))の原則に従います。

3
Jon Erickson

多くの人が定義と使用法について説明してきたので、重要な点のみを強調したいと思います

インターフェース:

  1. 契約を定義するには(できればステートレス-変数がないことを意味します)
  2. has a」機能を使用して無関係なクラスをリンクします。
  3. パブリック定数変数(不変状態)を宣言するには

抽象クラス:

  1. 密接に関連するいくつかのクラス間でコードを共有します。 「is a」の関係を確立します。

  2. 関連するクラス間で共通の状態を共有します(状態は具象クラスで変更できます)

小さな例で違いを閉じます。

Animalは抽象クラスにすることができます。 CatおよびDog、この抽象クラスを拡張すると、「is a」の関係が確立されます。

is a動物

is a動物。

Dogcan implement Barkインターフェース。次に、吠え声の犬has a機能。

Catcan implement Huntインターフェース。次に、ハンティングの猫has a機能。

not AnimalであるManは、Huntインターフェースを実装できます。次に、ハンティングのMan has a機能。

人と動物(猫/犬)は無関係です。ただし、ハントインターフェイスは、無関係のエンティティに同じ機能を提供できます。

Mixin:

  1. abstract classinterfaceの両方が必要な場合。それらのいくつかは新しい動作を再定義する必要があり、それらのいくつかは一般的な実装に固執する必要がある多くの無関係なクラスに新しいコントラクトを強制したい場合に特に便利です。 Mixinに共通の実装を追加し、必要に応じて他のクラスがコントラクトメソッドを再定義できるようにします

抽象クラスを宣言する場合は、これら2つの方法のいずれかに従います。

  1. すべての抽象メソッドをinterfaceに移動すると、私の抽象クラスがそのインターフェースを実装します。

    interface IHunt{
        public void doHunting();
    }
    abstract class Animal implements IHunt{
    
    }
    class Cat extends Animal{
        public void doHunting(){}
    }
    

関連するSEの質問:

インターフェースと抽象クラスの違いは何ですか?

3
Ravindra babu

「Mixin」の意味は、Joshua Blochの効果的なJava本で定義されています。同じ本の抜粋:

"mixinは、クラスがその「プライマリタイプ」に加えて実装できるタイプであり、いくつかのオプションの動作を提供することを宣言します。たとえば、Comparableは、クラスがインスタンスの順序付けを宣言できるミックスインインターフェイスです他の相互に比較可能なオブジェクトに関してこのようなインターフェイスは、オプション機能を型の主要機能に「混合」できるため、ミックスインと呼ばれます。 "

1
Sumit Sengar

抽象クラスは、そのすべてのメンバーが実装されているわけではないクラスであり、継承者が実装するために残されています。それは、その継承者にその抽象メンバーを実装することを強制します。抽象クラスはインスタンス化できないため、それらのコンストラクターをパブリックにすることはできません。]

C#の例を次に示します。

    public abstract class Employee
    {
        protected Employee(){} 
        public abstract double CalculateSalary(WorkingInfo workingInfo);//no implementation each type of employee should define its salary calculation method.
    }

   public class PartTimeEmployee:Employee
  {
    private double _workingRate;
    public Employee(double workingRate)
    {
     _workingRate=workingRate;
    }
    public override double CalculateSalary(WorkingInfo workingInfo)
    {
      return workingInfo.Hours*_workingRate;
    }

}

インターフェイスはクラスによって実装されるコントラクトであり、実装クラスのメンバーのシグネチャを宣言するだけで、それ自体には実装がありません。通常、インターフェイスを使用して、ポリモーフィズムを実装し、依存クラスを分離します。

C#の例を次に示します。

public interface IShape
{
int X{get;}
int Y{get;}
void Draw();
}

public class Circle:IShape
{
public int X{get;set;}
public int Y{get;set;}

public void Draw()
{
//Draw a circle
}
}

public class Rectangle:IShape
{
public int X{get;set;}
public int Y{get;set;}

public void Draw()
{
//Draw a rectangle
}
}
1
Beatles1692