12

最も優れた本「Head First Design Patterns」を読んだ後、私は同僚にパターンとデザイン原則の利点を広め始めました。私のお気に入りのパターンである戦略パターンの長所を称賛しているときに、私は一時停止する質問をされました。もちろん、戦略は継承と構成を使用します。同僚が「なぜ具象クラスの代わりに抽象基本クラスを使用するのですか?」 .
私は、「サブクラスに抽象メソッドを実装させ、ABC をインスタンス化させないようにする」ことしかできませんでした。しかし、正直なところ、この質問は私を無防備にさせました。

4

8 に答える 8

22

特定のメソッドを実装する必要がある場合は、インターフェイスを使用します。引き出すことができる共有ロジックがある場合は、抽象基底クラスを使用します。機能の基本セットがそれ自体で完成している場合は、concreate クラスを基本として使用できます。抽象基本クラスとインターフェイスを直接インスタンス化することはできません。これは利点の 1 つです。具象型を使用できる場合は、メソッドをオーバーライドする必要があり、それには「コードの匂い」があります。

于 2010-06-28T17:53:34.273 に答える
5

実装ではなくインターフェイスへのプログラムは、抽象クラスと具象クラスとはほとんど関係がありません。テンプレート メソッドのパターンを覚えていますか? 抽象または具象のクラスは、実装の詳細です。

また、具象クラスの代わりに抽象クラスを使用する理由は、メソッドを実装せずにメソッドを呼び出すことができるためです。ただし、代わりにサブクラスに実装したままにしておく必要があります。

インターフェイスへのプログラミングは別のことです。それは、API がどのように行うかではなく、を行うかを定義することです。そして、これはインターフェイスによって示されます。

1 つの重要な違いに注意してくださいprotected abstract。メソッドを使用できます。つまり、これは実装の詳細です。ただし、すべてのインターフェイス メソッドはパブリックであり、API の一部です。

于 2010-06-28T17:56:12.993 に答える
1

抽象基本クラスは通常、設計者が特定のタスクをすべてのクラスで同じ方法で実行し、他の動作はサブクラスに依存するアーキテクチャパターンを強制したいシナリオで使用されます。例:

public abstract class Animal{

public void digest(){

}

public abstract void sound(){

}
}

public class Dog extends Animal{
public void sound(){
    System.out.println("bark");
}
}

ストラタジーパターンは、行動にアロギズムの家族がいる場合に、構成的行動を使用するように設計者に求めます。

于 2010-06-29T05:27:51.617 に答える
1

まず第一に、ストラテジー パターンは最新の C# ではほとんど使用されるべきではありません。これは主に、関数ポインター、デリゲート、またはファーストクラス関数をサポートしない Java などの言語用です。古いバージョンの C# では、IComparer などのインターフェイスで表示されます。

抽象基本クラスと具象クラスに関して、Java での答えは常に「この状況ではどちらがうまく機能するか?」です。あなたの戦略がコードを共有できるなら、ぜひそうさせてください。

デザインパターンは、何かを行う方法の指示ではありません。それらは、私たちがすでに行ったことを分類する方法です。

于 2010-06-28T18:03:30.523 に答える
1

はい。ただし、インターフェイスを使用してクラスに特定のメソッドを実装させることもできます。

具象クラスではなく抽象クラスを使用するもう 1 つの理由は、抽象クラスは明らかにインスタンス化できないことです。場合によっては、これが発生したくない場合もあるため、抽象クラスが適しています。

于 2010-06-28T17:48:45.380 に答える
0

クライアントが「暗黙の動作契約」に依存している場合、それは実装に対して、および保証されていない動作に対してプログラムされています。コントラクトに従ってメソッドをオーバーライドすると、クライアントのバグが露呈するだけで、バグの原因にはなりません。

OTOH、問題のメソッドが非仮想である場合、そこにないコントラクトを想定する間違いは、問題を引き起こす可能性が低くなります。つまり、オーバーライドできないため、オーバーライドしても問題が発生することはありません。元のメソッドの実装が (コントラクトに従いながら) 変更された場合にのみ、クライアントを壊すことができます。

于 2010-06-28T18:27:17.657 に答える
0

基本クラスが抽象的か具体的かという問題は、クラス内のすべてのオブジェクトに共通の動作のみを実装した基本クラス オブジェクトが役立つかどうかに大きく依存します。WaitHandle を検討してください。「待機」を呼び出すと、何らかの条件が満たされるまでコードがブロックされますが、その条件が満たされていることを WaitHandle オブジェクトに伝える一般的な方法はありません。派生型のインスタンスのみをインスタンス化できるのではなく、「WaitHandle」をインスタンス化できる場合、そのようなオブジェクトは待機しないか、常に待機する必要があります。後者の動作はまったく役に立ちません。前者は便利だったかもしれませんが、静的に割り当てられた ManualResetEvent を使用してもほぼ同じように実現できます (後者はいくつかのリソースを浪費すると思いますが、

多くの場合、私の好みは、抽象基本クラスではなくインターフェイスへの参照を使用することだと思いますが、「モデル実装」を提供する基本クラスをインターフェイスに提供します。したがって、MyThing への参照を使用する場所では、「iMyThing」への参照を提供します。iMyThing オブジェクトの 99% (または 100%) が実際には MyThing である可能性がありますが、他の何かから継承した iMyThing オブジェクトが必要な場合は、そうすることができます。

于 2010-06-28T19:25:08.990 に答える
0

以下のシナリオでは、抽象基本クラスを優先します。

  1. 基本クラスはサブクラスなしでは存在できません => 基本クラスは単に抽象的であり、インスタンス化できません。
  2. 基本クラスはメソッドの完全または具体的な実装を持つことはできません => メソッドの実装は基本クラスであり、サブクラスのみが完全な実装を提供できます。
  3. 基本クラスはメソッド実装のテンプレートを提供しますが、メソッド実装を完了するには具象クラスに依存します - Template_method_pattern

上記のポイントを説明する簡単な例

Shapeは抽象的で、 のような具体的な形がなければ存在できませんRectangle。形が異なれば式も異なるため、クラスでは描画をShape実装できません。シナリオを処理するための最良のオプション:実装をサブクラスにShape任せるdraw()

abstract class Shape{
    int x;
    int y;
    public Shape(int x,int y){
        this.x = x;
        this.y = y;
    }
    public abstract void draw();
}
class Rectangle extends Shape{
    public Rectangle(int x,int y){
        super(x,y);
    }
    public void draw(){
        //Draw Rectangle using x and y : length * width
        System.out.println("draw Rectangle with area:"+ (x * y));
    }
}
class Triangle extends Shape{
    public Triangle(int x,int y){
        super(x,y);
    }
    public void draw(){
        //Draw Triangle using x and y : base * height /2
        System.out.println("draw Triangle with area:"+ (x * y) / 2);
    }
}
class Circle extends Shape{
    public Circle(int x,int y){
        super(x,y);
    }
    public void draw(){
        //Draw Circle using x as radius ( PI * radius * radius
        System.out.println("draw Circle with area:"+ ( 3.14 * x * x ));
    }
}

public class AbstractBaseClass{
    public static void main(String args[]){
        Shape s = new Rectangle(5,10);
        s.draw();
        s = new Circle(5,10);
        s.draw();
        s = new Triangle(5,10);
        s.draw();
    }
}

出力:

draw Rectangle with area:50
draw Circle with area:78.5
draw Triangle with area:25

上記のコードはポイント 1 とポイント 2 をカバーしています。draw()基本クラスに何らかの実装があり、サブクラス メソッドを呼び出してdraw()機能を完了する場合は、メソッドをテンプレート メソッドとして変更できます。

テンプレート メソッド パターンを使用した同じ例:

abstract class Shape{
    int x;
    int y;
    public Shape(int x,int y){
        this.x = x;
        this.y = y;
    }
    public abstract void draw();

    // drawShape is template method
    public void drawShape(){
        System.out.println("Drawing shape from Base class begins");
        draw();
        System.out.println("Drawing shape from Base class ends");       
    }
}
class Rectangle extends Shape{
    public Rectangle(int x,int y){
        super(x,y);
    }
    public void draw(){
        //Draw Rectangle using x and y : length * width
        System.out.println("draw Rectangle with area:"+ (x * y));
    }
}
class Triangle extends Shape{
    public Triangle(int x,int y){
        super(x,y);
    }
    public void draw(){
        //Draw Triangle using x and y : base * height /2
        System.out.println("draw Triangle with area:"+ (x * y) / 2);
    }
}
class Circle extends Shape{
    public Circle(int x,int y){
        super(x,y);
    }
    public void draw(){
        //Draw Circle using x as radius ( PI * radius * radius
        System.out.println("draw Circle with area:"+ ( 3.14 * x * x ));
    }
}

public class AbstractBaseClass{
    public static void main(String args[]){
        Shape s = new Rectangle(5,10);
        s.drawShape();
        s = new Circle(5,10);
        s.drawShape();
        s = new Triangle(5,10);
        s.drawShape();
    }
}

出力:

Drawing shape from Base class begins
draw Rectangle with area:50
Drawing shape from Base class ends
Drawing shape from Base class begins
draw Circle with area:78.5
Drawing shape from Base class ends
Drawing shape from Base class begins
draw Triangle with area:25
Drawing shape from Base class ends

メソッドとして作成する必要があると判断したら、ユーザーまたはクラスabstractの 2 つのオプションがあります。でメソッドを宣言し、クラスを を実装するクラスとして定義できます。interfaceabstractinterfaceabstractinterface

于 2016-06-03T09:36:22.607 に答える