0

Animal 親クラスを含む「animal」というパッケージがあるとしましょう。Cat は Animal から拡張され、Dog は Animal から拡張されます。ただし、Animal は次のように設計されています。

class Animal {
  int amount;
  Animal next; // Then a constructor initializes these.

  drinkWater(int n) { ... }
}

Cat & Dog クラスは次の構造に従います。

class Cat extends Animal {
  Cat(int amount, Animal next) {
    super(amount, next);
  }

  @Override
  drinkWater(int n) { .. }
}

それらのそれぞれには、次のようなメソッド、drinkWater() があります。

public void drinkWwater(int n) {
  amount -= n;
  if (amount < 0) amount = 0;
  if (next != null) next.drinkWater(n);
}

ここで私がやろうとしているのは、動物の「リンクされたリスト」を作成し、それぞれが順番に水を飲むことです。ただし、たとえば、猫が n 量の水を飲むと、n+1 量の水が猫に渡されます。

私の目的は、「元の動物のパッケージに触れるのではなく、水を飲む動作を 1 匹ずつ変える」という問題を解決するための解決策を見つけることです。私はクラスでその「有名な」素朴な解決策を持ってきました:

class InvokeStaticTypeBDrink {
  static void typeBdrink(Animal animal, int n) {
    animal.amount -= n;
    if (animal.amount < 0) animal.amount = 0;
    if (animal.next != null) {
      if (animal instanceof Cat)
        InvokeStaticTypeDrink.drinkWater(animal.next, n+1);
      else if (animal instanceof Dog)
        InvokeStaticTypeDrink.drinkWater(animal.next, n-1);
      else
        InvokeStaticTypeDrink.drinkWater(animal.next, n);
    }
  }
}

それから、私は研究を始めました。これは本当に迅速で汚い解決策に見えたからです。

そこで、「ビジターパターン」というデザインパターンを見つけました。さて、二重ディスパッチの問題を解決する非常にクールなパターンですが、私の側には問題があります: 訪問可能なインターフェース (accept() メソッドを宣言する) は、元の動物によって「実装」されなければなりません。しかし、私の目標は「元の動物のパッケージを変更するのではなく、飲料水の動作を変更する」ことです。私は何かが欠けていると確信しています。

では、ちょっとしたハックで、ビジター パターンがまだ機能すると思いますか、それとも別のパターン/ソリューションの方が優れていると思いますか? ありがとう。

4

2 に答える 2

2

元のクラスに触れたくない場合、ビジター パターンを適用する唯一の方法は、元のクラスを新しい (ラッパー) クラス内にラップすることです。

とにかく、一部の動物の行動を変更したいだけなら、あなたの状況では、それらの特定のクラスを拡張し、飲酒行動をオーバーライドします

次に、次のような猫を飼っています。

class NonThirstyCat extends Cat {
  Cat(int amount, Animal next) {
    super(amount, next);
  }

  @Override
  public void drinkWater(int n) {
    amount += n;
    if (amount < 0) amount = 0;
    if (next != null) next.drinkWater(n);
  }
}
于 2010-09-25T11:12:59.123 に答える
0

あなたの場合、サブクラス化は役に立たないと思います。

訪問者パターンは良いですが、変更しないと機能しませんAnimal。2つの提案があります。実際、私は3つ持っています:

  1. やらないでください。あなたの問題を再考してください。私には悪い設計のように見え、おそらく OOP のすべての原則を破っています。
  2. AOP を使用します。AspectJ の Google。

または(3)次のようなことを試してください:

class FixedAnimal extends Animal {
    public static Animal fix(Animal a) {
        Animal result = a;
        if (a instanceof Cat || a instanceof Dog)
            result = new FixedAnimal(a);
        if (a.next != null) a.next = fix(a.next);
        return result;
    }
    Animal a;
    FixedAnimal(Animal a) { 
        super(0, null); 
        this.a = a;
    }
    public void drink(int n) {
        // do stuff
        if (a.next != null) a.next.drink(n);
    }
}

もちろん、これは の使用法についていくつかの仮定を立てていAnimalますが、おそらく理解できるでしょう。

私のお勧めは#1です。または、達成したいことをより具体的にします。

于 2010-09-25T11:18:40.727 に答える