なぜ誰かがビジターパターンを使いたいのでしょうか?いくつかの記事を読みましたが、何も得られません。
カスタムを請求する機能が必要な場合は、
Custom.Accept(BillVisitor)
またはのようなもの
Bill(Customer)
2つ目はそれほど複雑ではなく、Bill関数はCustomerクラスから分離されています。では、なぜビジターパターンを使用したいのでしょうか。
なぜ誰かがビジターパターンを使いたいのでしょうか?いくつかの記事を読みましたが、何も得られません。
カスタムを請求する機能が必要な場合は、
Custom.Accept(BillVisitor)
またはのようなもの
Bill(Customer)
2つ目はそれほど複雑ではなく、Bill関数はCustomerクラスから分離されています。では、なぜビジターパターンを使用したいのでしょうか。
この問題は、複雑な構造、つまり階層など、単純に線形ではないものがある場合に発生します。構造を単純に繰り返すことができない場合、訪問者は非常に便利です。
階層(またはツリー)がある場合、各ノードには子のリストがあります。ツリー内のすべてのノードにプロセスを適用したい場合は、Visitorを作成するのが楽しいです。
その後、ノードはビジターをそれ自体とその子ノードのそれぞれに適用できます。各子は、推移的に同じことを行います(ビジターを自分自身に適用してから、すべての子に適用します)。
ビジターのこの使用は非常にうまくいきます。
非常に単純なデータ構造の場合、Visitorは多くの価値を追加しません。
ビジター パターンは、複数のディスパッチを直接サポートしていない言語のハックです (C++ や Java などの言語は、オブジェクトに基づく単一のディスパッチのみをサポートします。複数のディスパッチは CLOS でサポートされています)。この場合、Bill と Customer の両方をポリモーフィックにしたい場合は、単一のディスパッチ言語で BillVisitor と Customer の 2 つのインターフェイスを使用する必要があります。例: 通常、accept の実装は次のとおりです。
void accept(BillVisitor visitor) { visitor.bill(this); } // java syntax
ここで、Customer#accept と BillVisitor#bill の両方をそれぞれのサブクラスでオーバーライドできることに注意してください。これにより、他の方法では実現できないランタイム動作の非常に豊富な組み合わせが得られます。これは、複雑なデータ構造に機能を適用するためのクロージャーの代わりとして、ここで他のほとんどの人が説明したもののスーパーセットです。
ビジターのもう 1 つの利点は、簡単に拡張できることです。言語で許可されている場合は、lamdbas を使用してクリーンアップすることもできます。
どちらの場合も、訪問者は顧客クラスから分離されています。呼び出し元クラスからもビジターを抽象化したい場合に利点があります。2 番目のケースでは、呼び出し元のクラスは課金について知っている必要があります。代わりに、IVisitor を返す別のルーチンをどこかに置くことができます。呼び出し元のコードは Custom.Accept(IVisitor) を呼び出し、訪問者が何をしているかについて何も知らない可能性があります。
基本的に、このケースと S.Lott が言及したケースでは、訪問者をデリゲートのように考えることができます。これは、オブジェクトのように渡し、必要な場所で使用できる関数です。