Visitor パターン

「Visitor」という英単語は、「訪問者」を意味します。

このパターンは、「データ構造」と「それに対する処理」を分離することを目的とするパターンです。そのためこのパターンを適用すると、「データ構造」を変更することなしに、「新しい処理」を追加することができます。

具体的には、訪問者であるVisitor役のオブジェクトが、訪問先であるデータ構造要素の個々のオブジェクトを訪問し、その訪問先の公開されている資源を利用して処理を実行して回るという形になります。(データ構造役オブジェクトは、処理を訪問者役オブジェクトに委任する)


役割り

1. Visitor(訪問者)

具体的なデータ構造の要素(ConcreteAcceptorA・ConcreteAcceptorB)毎に訪問して行う処理(visitメソッド)のインタフェースを定義します。

※visitメソッドは、 オーバーロードする事でその訪問先要素の型に応じた処理を指定します。

2. ConcreteVisitorA・B(具体的訪問者)
「Visitor」で定義したインタフェース(各visitメソッド)を実装します。
3. Acceptor(データ構造(受入者))
「Visitor」の訪問先であるデータ構造要素に、受入口(acceptメソッド)のインタフェースを定義します。
4. ConcreteAcceptorA・B(具体的データ構造(受入者))
「Acceptor」で定義したインタフェース(acceptメソッド)を実装します。
5. Client(利用者)
「Visitor」パターンを適用したクラスを用い処理を行います。

▲PageTop

クラス図

Visitorパターンのクラス図

Visitorパターン クラス図

▲PageTop

シーケンス図

Visitorパターンのシーケンス図

Visitorパターン シーケンス図

Visitorパターンでは、受入者「ConcreteAcceptor」のメソッドacceptを呼出すと、訪問者「ConcreteVisitor」のメソッドvisitが呼出され、実行する処理が決定します。この様な2重呼出しを一般的に「ダブルディスパッチ(2重振分け)」と呼びます。

▲PageTop

サンプル

ソースコード

1. Visitor.java

public abstract class Visitor {
    public abstract void visit(ConcreteAcceptorA acceptorA);
    public abstract void visit(ConcreteAcceptorB acceptorB);
}

2-1. ConcreteVisitorA.java

public class ConcreteVisitorA extends Visitor {
    private String name = "ConcreteVisitorA";
    public void visit(ConcreteAcceptorA acceptorA) {
        System.out.println(name + " が " + acceptorA.getName() + " を訪問しました。");
    }
    public void visit(ConcreteAcceptorB acceptorB) {
        System.out.println(name + " が " + acceptorB.getName() + " を訪問しました。");
    }
}

2-2. ConcreteVisitorB.java

public class ConcreteVisitorB extends Visitor {
    private String name = "ConcreteVisitorB";
    public void visit(ConcreteAcceptorA acceptorA) {
        System.out.println(name + " が " + acceptorA.getName() + " に参りました。");
    }
    public void visit(ConcreteAcceptorB acceptorB) {
        System.out.println(name + " が " + acceptorB.getName() + " に参りました。");
    }
}

3. Acceptor.java

public abstract class Acceptor {
    public abstract void accept(Visitor visitor);
}

4-1. ConcreteAcceptorA.java

public class ConcreteAcceptorA extends Acceptor {
    private String name = "ConcreteAcceptorA";
    public String getName() {
        return name;
    }
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }
}

4-2. ConcreteAcceptorB.java

public class ConcreteAcceptorB extends Acceptor {
    private String name = "ConcreteAcceptorB";
    public String getName() {
        return name;
    }
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }
}

5. Client.java

public class Client {
    public static void main(String[] args) {
        Visitor viA = new ConcreteVisitorA();
        Visitor viB = new ConcreteVisitorB();
        Acceptor acA = new ConcreteAcceptorA();
        Acceptor acB = new ConcreteAcceptorB();
        acA.accept(viA);
        acB.accept(viA);
        acA.accept(viB);
        acB.accept(viB);
    }
}

実行結果

C:\sample\desin_pattern\visitor>javac Client.java [Enter]

C:\sample\desin_pattern\visitor>java Client [Enter]
ConcreteVisitorA が ConcreteAcceptorA を訪問しました。
ConcreteVisitorA が ConcreteAcceptorB を訪問しました。
ConcreteVisitorB が ConcreteAcceptorA に参りました。
ConcreteVisitorB が ConcreteAcceptorB に参りました。
        

▲PageTop