0

コンポジションと継承の違いを探している人は、どこかでこの投稿を見つけました。

投稿によると、構成はコードの再利用において継承よりも優れています。

class Fruit {

    // Return int number of pieces of peel that
    // resulted from the peeling activity.
    public int peel() {

        System.out.println("Peeling is appealing.");
        return 1;
    }
}

class Apple {

    private Fruit fruit = new Fruit();

    public int peel() {
        return fruit.peel();
    }
}

class Example2 {

    public static void main(String[] args) {

        Apple apple = new Apple();
        int pieces = apple.peel();
    }
}

バックエンド クラスを変更する

class Peel {

    private int peelCount;

    public Peel(int peelCount) {
        this.peelCount = peelCount;
    }

    public int getPeelCount() {

        return peelCount;
    }
    //...
}

class Fruit {

    // Return int number of pieces of peel that
    // resulted from the peeling activity.
    public Peel peel() {

        System.out.println("Peeling is appealing.");
        return new Peel(1);
    }
}

// フルーツへの変更に対応するために // Apple を変更する必要があります

class Apple {

    private Fruit fruit = new Fruit();

    public int peel() {

        Peel peel = fruit.peel();
        return peel.getPeelCount();
    }
}

// この Example2 の古い実装は // まだ問題なく動作します。

class Example1 {

    public static void main(String[] args) {

        Apple apple = new Apple();
        int pieces = apple.peel();
    }
}

これは、「バックエンドクラスのインターフェースが変更された場合、フロントエンドクラスの実装も変更されますが、そのインターフェースは変更されません」という投稿によると、私が得られなかったものです。

ここでのインターフェースは何ですか?実装は何ですか?

これは私の仮定です.IMが間違っている場合は教えてください??(多分すべてが間違っています).

フロントエンドクラスが依存しているため、バックエンドクラスはインターフェースですか? フロントエンドクラスの実装はフロントエンドクラス内の実装コードですか?Example内のコードが依存しているため、フロントエンドクラスもインターフェース ですか?

バックエンド インターフェースの変更がフロントエンドインターフェースに変更を加えていないため、これらは疎結合ですか? したがって、フロントエンド インターフェイスに依存するコードは引き続き機能します。

代わりに継承を使用すると、サブクラスはスーパークラスで密結合されますか? スーパークラスに変更するとサブクラスにも変更されるため、サブクラスに依存するコードは動作しない可能性があります。

Wny 継承は弱いカプセル化です。

4

1 に答える 1

3

これがApple と Fruit の間で行われるべき直感的な継承関係です。ただし、これは上記の例が行ったことではありません。

ここに画像の説明を入力

上記の例ではコンポジションを使用しています。つまり、コンポジションFruitは(uml hereを参照)の一部です 。これはかなり直感に反しています!この場合、 と の両方にピールの個別の実装があります。in usesの実装。AppleFruitApplepeel()AppleFruit.peel()

ここに画像の説明を入力

Appleとの構成関係を使用する場合Fruit、その実装は Fruit から独立できるということが指摘されていると思います。たとえば、Fruit.peel()のカウントを取得するために を使用する代わりにApple.peel()、他の実装を使用できます。しかし、Appleが から ピール を継承するFruitと、 の変更Fruitも変更されますApple。したがってApple、 は から独立していないFruitため、密結合であると言えます。

これはいくつかの点で悪い例です。1) リンゴが果物であることは誰もが知っている ので、継承が最も正しい実装のように思えます。2) 継承は、物事を実装するための最もドライな方法のようです。なぜなら、コンポジションを使用するには、変更が行われたときAppleと同じことを行うようにクラスを修正する必要があるためです。FruitFruit.peel()

編集:記事を読んで、主なポイントは継承を使用する際の落とし穴の概要を説明することだと思います。継承を適切に使用することに問題はありません。コードを再利用するためだけに使用すると、子クラスが実際にはスーパー クラスから動作を継承しない場合に問題が発生する可能性があります。

あなたの質問に答えるために!

フロントエンドクラスが依存しているため、バックエンドクラスはインターフェースですか?

十分近い。すべてのクラスには「インターフェース」があります。これはimplements IFruit、クラス宣言に文字どおり含まれているという意味ではなく、オブジェクトの形状(メソッドの動作に関係なく、オブジェクトが持つメソッド) を参照しているだけです。

フロントエンドクラスの実装はフロントエンドクラス内の実装コードですか?

おおよそ、はい。クラスのメソッドの本体を構成するコードの実際のロジックは、そのクラスの実装です。

Example内のコードが依存しているため、フロントエンドクラスもインターフェースですか?

かなり。Apple他のクラスと同様に、暗黙的にインターフェースを持っています。クラスをExample使用する場合は、インターフェースの一部であるメソッドを使用することによってのみ可能です。Apple

バックエンド インターフェースの変更がフロントエンド インターフェースに変更を加えていないため、それらは疎結合ですか?

ええ、それは「疎結合」というフレーズの 1 つの使用方法です。

代わりに継承を使用すると、サブクラスはスーパークラスで密結合されますか? スーパークラスに変更するとサブクラスにも変更されるため、サブクラスに依存するコードは動作しない可能性があります。

はい、そうです。2 つのクラスは、その動作がそれぞれの個別のクラスに完全にカプセル化されていないという点で密接に結合されています。これは常に間違っているわけではなく、状況によって異なります。

Wny 継承は弱いカプセル化です。[原文のまま]

スーパークラスとサブクラスの間で動作が共有されるためです。

于 2012-05-15T01:18:58.157 に答える