5

似たような質問が既にあると言う前に、はい、知っています、読んだことがあります。しかし、そこでの質問はいつに焦点を当てているので、私はその理由に興味があります。

私は物事がどのように機能するかを理解しています。古典的な動物、犬、猫の例は常に魅力的です。

問題はこのコードです

int main()
{
    Cat c;
    Sound theSound;
    c.letsDo(&theSound);
}

私にはとても不自然に思えます。なんで?

つまり、そうです、この方法で犬と猫のモデルを区別しませ(英語でその単語を初めて使用します)。実際の実装は Sound クラスの下に隠されていますが、それは単にコードを重くする方法ではないからです。 ? このようなことを行うにはポリモーフィズムで十分ではありませんか?

私にとっての違いは、ポリモーフィズムでは各クラスを編集する必要があることです (ただし、モデルは同じままですよね?)。一方、ビジター デザイン パターンでは 1 つのクラスを編集するだけで済みます。

4

4 に答える 4

8

ビジター パターンを使用すると、単純にポリモーフィズムに依存するだけではできないことを実行できます。予期しないユース ケースに対応できます。ライブラリを作成している場合、これは重要なポイントです。詳しく説明しましょう:

ビジター パターンの使用に関する古典的な例、つまり、抽象構文ツリーのノードに対する操作を考えてみましょう。詳細を追加するために、たとえば、文字列を取得して解析し、入力で見つかったものの AST を返す SQL 用のパーサー ライブラリを作成したとします。クライアント コードがそのような AST に対して持つ可能性のあるすべての潜在的なユース ケースを予測できない限り、AST を実行するための "一般的な" 方法を提供する必要があります。DOM のようなアクセサ関数 ( getNodeTypegetParentNodegetPreviousNode) を提供するのも 1 つの方法です。ここでの問題は、ディスパッチを自分で行う必要があるため、ライブラリのクライアントに大きな負担がかかることです。さらに、可能性のあるノード タイプごとにどのポインタに従うべきかを詳細に知る必要があります。

void 
walk_tree(AstNode* node) 
{
    switch( node->getNodeType() ) {
    case SELECT_NODE:
        for( AstNode* child = node->getFirstChild(); child; child = child->getNextNode() ) {
             walk_tree(child);
        }
        break;
    ...
    }
}

ビジター パターンは、この負担をクライアントからライブラリに移します。

于 2010-09-10T15:08:52.643 に答える
3

所有していないライブラリにいくつかの基本的なものが定義されていて、それを拡張する必要があるとしましょう。お気に入り:

// In base lib:
interface ISomething {
    void DoSomething();
}

class Something1 : ISomething {
    // ...
}

class Something2 : ISomething {
    // ...
}

ポリモーフィズムにより、操作を実行できる新しいものを定義できます。

// In your lib:
class MySomething : ISomething {
}

これで、ベース lib はMySomething、あたかもそれが定義されているかのように動作することができます。できないことは、新しい操作を追加することです。DoSomethingでできる唯一のことですISomething。Visitor パターンはそれに対処します。

欠点は、ビジター パターンを使用すると、先ほど示したような新しい型を定義する能力が犠牲になることです。ほとんどの言語では、操作または型のいずれかを簡単に追加できるが、両方を追加できないという事実は、式の問題と呼ばれます。

ビジター パターンは素晴らしいものですが、コンパイラの実装以外で実際にその必要性を感じたことはありません。

于 2010-09-13T01:06:26.197 に答える
2

Visitor パターンは非常に便利です。

それを使用する少なくとも 3 つの大きな理由があります。

  1. データ構造が変更されたときにわずかにしか変わらないコードの増殖を減らします。

  2. 計算を実装するコードを変更せずに、同じ計算をいくつかのデータ構造に適用します。

  3. 従来のコードを変更せずに、従来のライブラリに情報を追加します。

これについて私が書いた記事を見てください。

乾杯

于 2011-01-29T23:09:50.527 に答える
1

オブジェクトのツリーがあり、コンテンツをさまざまな方法で印刷する必要があるときに、ビジター パターンを使用しました。カンマ区切り、XML など。出力形式ごとに新しい print メソッドをツリー クラスに追加する代わりに、ビジター パターンを使用して、CommaSepVisitor、XMLVisitor、および HTMLVisitor クラスを作成しました。ビジター タイプを追加してもツリー コードは変更されなかったので、バグが発生することはありませんでした。来場者自身も書きやすかったです。

于 2010-10-16T21:37:29.347 に答える