-1

私は多重継承を研究していますが、それは設計が悪いと考えられていることを読みました。

多重継承が役立つ例を作成しましたが、多重継承を削除するように書き直す方法が見つかりませんでした。
さらに、多くの言語は多重継承をサポートしておらず、新しい設計が必要です。

「Animal」クラスは、すべての動物が行う多くのことを実装しています。
「AquaticAnimal」クラスは、水に関するすべてを実装します。
「TerrestrialAnimal」クラスは、陸上の動物に関するすべてを実装します。

「水陸両用」クラスは、「AquaticAnimal」と「TerrestrialAnimal」ができるすべてのことができる動物のために作成されました。
アプリケーションは、クラスで「水陸両用」の動物を使用する必要があります: Zoo、Aquarius、Plains、および AmphibiousRace。

仮想継承にもかかわらず、Amphibious.eat() を呼び出すと Animal.eat() が 2 回呼び出され、一貫性のない状態になるため、ダイヤモンドの問題は続きます。

これは実際のプログラミング言語ではありませんが、Java/C++ に似ています。

class Animal{
  private:
    Place birthplace;
    String name;
    List likesToEat;
    Stomach stomach;

  public:
    virtual void growl(){ ... }

    virtual int eat(Food food){
        ... test if likes
        ... many operations
        chew()
        ...
        stomach.fill(food);
    }
}

class FlyingAnimal extends Animal {
  private:
    Wings wings;
  public:
    void fly(){ ...  wings.move(); ... }
}
class AquaticAnimal extends Animal{
  private:
    Flipper flipper;

  public:
    void swim(){ ... flipper.move(); ...  }

    int eat(Food food){
       int x = Animal.eat(food);
       ... use x
       flipper.nourish(food);
    }
}
class TerrestrialAnimal extends Animal{
  private:
    Legs legs;

  public:
    void run(){ ... legs.move(); ...  }

    int eat(Food food){
       int x = Animal.eat(food);
       ... use x
       legs.nourish(food);
    }
}
class Amphibious extends AquaticAnimal, TerrestrialAnimal{
  public:
    int eat(Food food){
        AquaticAnimal.eat(food);
        TerrestrialAnimal.eat(food);
        //PROBLEM: Animal.eat() will be called twice.
    }
}

//------------------------------------------
class Zoo {
  public:
    void add/remove(Animal a);
    void feed(Animal a);
    void show(Animal a);
}
class Aquarius {
  public:
    void add/remove(AquaticAnimal a);
}
class Plains {
  public:
    void add/remove(TerrestrialAnimal a);
}
class HighPeaks {
  public:
    void add/remove(FlyingAnimal a);
}
class AmphibiousRace {
  public:
    void add/remove(Amphibious a);
    void enterIntoLake(Amphibious a);
    void exitFromLake(Amphibious a);
}
4

1 に答える 1

0

水生動物と陸生動物を区別するのが脚と足ひれである場合、水陸両用動物が両方から継承されていると言うのは本当に有効ですか? 足と足ひれの両方を持っている動物は多くありません。

いずれにせよ、必要な部分をクラスに渡すという、より多くの構成アプローチを使用できます。

class Animal{
  private:
    Place birthplace;
    String name;
    List likesToEat;
    Stomach stomach;

  public:

    virtual IEnumerable<Movement > Movements { get; }
    virtual IEnumerable<IAppendage> Appendages{ get; }

    virtual void growl(){ ... }

    virtual int eat(Food food){
        ... test if likes
        ... many operations
        chew()
        ...
        stomach.fill(food);
    }
}

interface IAppendage {
   void Move();
}

class Wings : IAppendage {}
class Legs: IAppendage {}
class Flippers : IAppendage {}


class Movement {
  private:
  IAppendage AppendageForMovement { get; }
  public :
  void Go(){
    AppendageForMovement.Move();
  }
}

class FlyingMovement : Movement {}
class RunningMovement : Movement  {}
class SwimmingMovement : Movement {}

class AmphibiousAnimal extends Animal {

private: 
   Flippers flipper;
   Legs leg;
    virtual IEnumerable<Movement > Movements { get { return new Movement [] { new SwimmingMovement( flipper ), new RunningMovement( leg ) } ; }
    virtual IEnumerable<IAppendage> Appendages { get { return new IAppendage[] {new Wings() } }

  public:
    void fly(){ // find flying movement
           ...  
           flyingMovement.Go(); 
           ... 
    }
}

ちょっと大雑把な例ですが、参考になれば幸いです。すべての機能を基本クラスに結び付けようとする代わりに、必要な機能を渡してみてください。複数のタイプの機能 (ランニング、ウォーキング、水泳など) が必要な場合は、その機能を提供するヘルパー クラスを渡すだけです。

于 2012-05-03T02:33:29.513 に答える