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() メソッドを宣言する) は、元の動物によって「実装」されなければなりません。しかし、私の目標は「元の動物のパッケージを変更するのではなく、飲料水の動作を変更する」ことです。私は何かが欠けていると確信しています。
では、ちょっとしたハックで、ビジター パターンがまだ機能すると思いますか、それとも別のパターン/ソリューションの方が優れていると思いますか? ありがとう。