私はVisitor Patternをよくマスターします。しかし、私は何か疑問に思っています。
ビジター パターンを使用する最も重要な動機は、実際のデータ オブジェクト タイプをチェックする必要なく、クライアント側で特定のデータ モデルを含むロジックを追加することです。解決に使用される手法は、Double-Dispatching と呼ばれます。
したがって、accept()
メソッドを実装するデータ モデルのコード スニペットは次のとおりです。
public class Ferrari extends Car {
//......
@Override
public void accept(Visitor v){
v.visit(this);
}
}
そしてここにPrintCarVisitor
実装Visitor
インターフェースがあります:
public class PrintCarVisitor implements Visitor {
//...
@Override
public void visit(Ferrari c){
System.out.println("Ferrari");
}
}
したがって、if/else
シリーズとinstanceof
シリーズは必要ありません。
すべてのクライアントは次のようになります。
Visitor visitor = new PrintCarVisitor();
car.accept(visitor); //no need to know the exact Car's type
しかし、Visitor は Open/Closed Principle を保持していないため (新しいデータ モデルが独自のvisit
メソッドを追加することでクラスを破壊するため)、なぜわざわざ二重ディスパッチを行うのでしょうか?
if/else
ビジターの実装内でシリーズを分離することはできませんか。
この仮想的な代替案を使用すると、コードのこの部分が消えます。
public class Ferrari extends Car {
//This method is not needed anymore with this alternative
@Override
public void accept(Visitor v){
v.visit(this);
}
}
PrintCarVisitor
だろう:
public class PrintCarVisitor {
public void visit(Car c){
if(c instanceof Ferrari){
System.out.println("Ferrari");
}
}
}
この代替手段を使用しても、すべての呼び出し元は、次のようにデータ モデルの抽象化を処理します。
new PrintCarVisitor().visit(car); //no need to know the exact data type in client side
アプリオリに、この 2 番目のアプローチは、純粋な Visitor パターンの実装中に生成されるすべてのボイラープレートを必要としないため、優れています。
このアプローチには 2 つの欠点があると思います。
1)Visitor
使用されたビジターがCar
現在処理されているメソッドに対応するメソッドを破棄するという保証はありません (インターフェイスが課すように)。
2) BoilerPlate コードは、一連のinstanceof
およびを使用して、Visitor 実装クラスにより重いままcasting
です。
Visitor Pattern が Double Dispatching を使用する必要がありinstanceof
、クラス内でシリーズを単純に分離できない理由を説明する他の欠点はありますか (Factory
たとえば、静的なように)?