4

私はイテレータとビジターの両方をよく知っていて、頻繁に使用しており、Gang of Four のデザイン パターンについて聞く前から両方を使用していました。2 つのパターンの構文はかなり異なりますが、オブジェクトのグループをトラバースするという同じ概念上の目標のために両方を使用します。大まかに言えば、同じ型の非構造化オブジェクトがある場合は反復子を使用し、異なる型の構造化オブジェクトがある場合はビジターを使用します。私にとって、ビジターはエレガントで派手な、より強力な型付けイテレーターにすぎません。

デザイン パターンを読んだとき、ビジターの説明、特にイテレータの説明との違いに気付きました。

ビジターを使用すると、操作対象の要素のクラスを変更せずに新しい操作を定義できます

イテレーター: 基になる表現を公開せずに、集約オブジェクトの要素に順番にアクセスする方法を提供します。

それ以来、私はそれについて考えてきましたが、訪問者が新しい操作をどのように定義するかを実際には理解できません。

たとえばtoLocalizedString()、のローカライズされた代替手段として、かなり単純な操作を実装したい場合toString()。ビジターを要素に渡すと、そのオブジェクトのサブ構造全体をトラバースします。さらに、accept/visit メソッドからは何も返すことができません。これらの各特性により、私はビジターを使用して を定義することができませんtoLocalizedString()

そして、これは私の質問をもたらします:イテレータがしない方法で、ビジターはどのように「新しい操作を定義する」のでしょうか? ギャング オブ フォーの説明を信じるなら、ビジター パターンの真の力を見逃しているように感じます。

4

2 に答える 2

5

構造のトラバーサルは、ビジター パターンを定義する機能ではありません。実際、ビジターを使用して、構造を持つオブジェクトを巧妙な反復子としてトラバースすることを考えることができます。

ビジターとイテレーターの違いは、ビジターではいわゆるDouble Dispatchを実行できることです。つまり、ビジター オブジェクトのランタイム タイプとビジター オブジェクトの両方に依存するメソッドにメッセージをルーティングします。訪問されるオブジェクトはビジターの外部にありますが、操作の実行可能コードはビジターの内部に含まれています。つまり、訪問者パターンに従うことで、訪問されているオブジェクトの外部にある操作を実行できます。これは、オブジェクトに対する新しい操作を定義することと考えることができます。

于 2013-06-20T19:34:10.090 に答える
0

訪問者に新しい操作を導入できない理由として、次のことを特定しました。

  1. 「要素にビジターを渡すと、そのオブジェクトのサブ構造全体をトラバースします。」
  2. 「さらに、accept/visit メソッドからは何も返すことができません。」

理由 (1) は多くの場合、妥当な懸念事項であると思います。ただし、ビジターを変更してこれを回避できると思います。構造の探索を続行するかどうかを示すを作成visitしてaccept返すとします。boolean次に、次のような作業を行うことができますaccept(疑似コードで):

 for (each child) {
     if (!child.accept(visitor)) return false;
 }
 return visitor.visit(this);

そうすれば、訪問者は検索が完了したことを認識するとすぐに、検索を停止できます。これは、互いにリンクされたオブジェクトの深さ優先バックトラッキング検索を行うことに似ています。

ただし、(2) については、訪問者に関する重要なテクニックが欠けていると思います。訪問者はオブジェクトであるため、非公開の状態情報を含めることができます。たとえばcount、構造体の要素の総数を返す単純な関数を書きたいとします。次に、次のように書くことができます。

public int count(Base object) {
    Visitor v = new Visitor() {
        private int numElems = 0;

        public void visit(Base object) {
            numElems++;
        }
        public void visit(Derived1 object) {
            numElems++;
        }
        // ... etc

        public int getCount() {
            return numElems;
        }
    };
    object.accept(v);
    return v.getCount();
}

visitここでand acceptreturnしてもvoid、訪問者に内部状態を維持させ、訪問が完了したらその状態を返すことによって、値を返す全体的なメソッドを構築できることに注意してください。これからは、count(obj)wil;を呼び出します。すべてのオブジェクトの数を返します。基本的に、追加のメソッドをクラス階層に「移植」します。

お役に立てれば!

于 2013-06-20T19:34:51.020 に答える