LoginSignup
0
0

More than 3 years have passed since last update.

Visitorパターン

Posted at

Visitorパターンとは

データ構造と処理を分離する。
データ構造を巡り歩く訪問者を表すクラスを用意し、そのクラスに処理を任せる。
データ構造側は、訪問者を受け入れてやる。

Visitor(訪問者)の役

Visitor役はデータ構造の具体的な要素(ConcreteElement役)ごとに「xxxを訪問した」という
visit(xxx)メソッドを宣言する。
visit(xxx)はxxxを処理するためのメソッドで、実際のコードはConcreteVisit役の側に書かれる。

package visitor;

public abstract class Visitor {
    public abstract void visit(File file);
    public abstract void visit(Directory directory);
}

ConcreteVisitor(具体的訪問者)の役

ConcreteVisitor役はVisitor役のインターフェースを実装する。
visit(xxx)という形のメソッドを実装し、個々のConcreteElement役ごとの処理を記述する。

package visitor;

import java.util.Iterator;

public class ListVisitor extends Visitor{
    private String currentDir = "";

    @Override
    public void visit(File file) {
        System.out.println(currentDir + "/" + file);
    }

    public void visit(Directory directory) {
        System.out.println(currentDir + "/" + directory);
        String savedDir = currentDir;
        currentDir = currentDir + "/" + directory.getName();
        Iterator<Entry> it = directory.iterator();
        while (it.hasNext()) {
            Entry entry = it.next();
            entry.accept(this);
        }
        currentDir = savedDir;
    }
}

Element(要素)の役

Element役はVisitor役の訪問先を表す役。
訪問者を受け入れるacceptメソッドを宣言する。
acceptメソッドの引数にはVisitor役が渡される。

package visitor;

public interface Element {
    public abstract void accept(Visitor v);
}

ConcreteElement(具体的要素)の役

ConcreteElement役はElement役のインターフェースを実装する役。

package visitor;

public class File extends Entry{
    private String name;
    private int size;

    public File(String name, int size) {
        this.name = name;
        this.size = size;
    }

    public String getName() {
        return name;
    }

    public int getSize() {
        return size;
    }

    @Override
    public void accept(Visitor v) {
        v.visit(this);
    }
}
package visitor;

import java.util.ArrayList;
import java.util.Iterator;


public class Directory extends Entry{
    private String name;
    private ArrayList<Entry> directory = new ArrayList<>();

    public Directory(String name) {
        this.name = name;
    }

    @Override
    public String getName() {
        return name;
    }

    @Override
    public int getSize() {
        int size = 0;
        Iterator<Entry> it = directory.iterator();
        while (it.hasNext()) {
            Entry entry = (Entry) it.next();
            size += entry.getSize();
        }
        return size;
    }

    public Entry add(Entry entry) {
        directory.add(entry);
        return this;
    }

    public Iterator<Entry> iterator() {
        return directory.iterator();
    }

    public void accept(Visitor v) {
        v.visit(this);
    }
}

ObjectStructure(オブジェクト構造)の役

ObjectStructure役はElement役の集合を扱う役。
ConcreteVisitor役が個々のElement役を扱えるようなメソッドを備えている。
この役は上記のDirectoryクラスが該当する。

呼び出し元

package visitor;

public class Main {
    public static void main(String[] args) {
        try {
            System.out.println("Making root entries...");
            Directory rootDir = new Directory("root");
            Directory binDir = new Directory("bin");
            Directory tmpDir = new Directory("tmp");
            Directory usrDir = new Directory("usr");
            rootDir.add(binDir);
            rootDir.add(tmpDir);
            rootDir.add(usrDir);
            binDir.add(new File("vi", 10000));
            binDir.add(new File("latex", 20000));
            rootDir.accept(new ListVisitor());

            System.out.println();
            System.out.println("Making user entryies...");
            Directory yuki = new Directory("yuki");
            Directory hanako = new Directory("hanako");
            Directory tomura = new Directory("tomura");
            usrDir.add(yuki);
            usrDir.add(hanako);
            usrDir.add(tomura);
            yuki.add(new File("diary.html", 100));
            yuki.add(new File("Composite.java", 200));
            hanako.add(new File("memo.tex", 300));
            tomura.add(new File("game.doc", 400));
            tomura.add(new File("junk.mail", 500));
            rootDir.accept(new ListVisitor());
        } catch (FileThreatmentException e) {
            e.printStackTrace();
        }
    }
}

実行結果

スクリーンショット 2020-09-16 18.12.57.png

こちらを参考にさせていただきました。
増補改訂版Java言語で学ぶデザインパターン入門

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0