Index
Java言語で学ぶデザインパターン入門第3版
参考書籍では以下のように説明されていました。
Visitorパターンでは、データ構造と処理を分離します。
- 処理をデータ構造から分離することができる
Compositeパターンの記事で使ったサンプルコードを拡張していきます。
Compositeパターン@Java言語によるデザインパターン入門
ファイルとディレクトリで構成されたデータ構造の中を訪問者が渡り歩き、ファイルの一覧を表示するプログラムを作成します。
クラス図はこんな感じ。
訪問者を表す抽象クラス。
visit(File)メソッドはFileを訪問したときにFileクラスが呼び出す
visit(Directory)メソッドはDirectoryを訪問したときにDirectoryクラスが呼び出す
1 2 3 4 |
public abstract class Visitor { public abstract void visit(final File file); public abstract void visit(final Directory directory); } |
訪問者(Visitorクラス)を受け入れるインターフェースです。
1 2 3 |
public interface Element { public abstract void accept(final Visitor visitor); } |
EntryをVisitorパターンに適合させるためにElementインターフェースを実装しています。
1 2 3 4 5 6 7 8 9 10 |
public abstract class Entry implements Element{ public abstract String getName(); public abstract int getSize(); @Override public String toString() { return getName() + "(" + getSize() + ")"; } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
public class File extends Entry{ private final String m_name; private final int m_size; public File(final String name, final int size) { m_name = name; m_size = size; } @Override public String getName() { return m_name; } @Override public int getSize() { return m_size; } @Override public void accept(final Visitor visitor) { visitor.visit(this); } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.stream.Collectors; public class Directory extends Entry implements Iterable<Entry>{ private final String m_name; private List<Entry> m_directory = new ArrayList<>(); public Directory(final String name) { m_name = name; } @Override public String getName() { return m_name; } @Override public int getSize() { return m_directory.stream() .collect(Collectors.summingInt(entry -> entry.getSize())); } //ディレクトリエントリをディレクトリに追加する public Entry add(final Entry entry) { m_directory.add(entry); return this; } @Override public void accept(final Visitor visitor) { visitor.visit(this); } @Override public Iterator<Entry> iterator() { return m_directory.iterator(); } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
public class ListVisitor extends Visitor{ private String m_currentDir = ""; //File訪問時 @Override public void visit(final File file) { System.out.println(m_currentDir + "/" + file); } //Directory訪問時 @Override public void visit(final Directory directory) { System.out.println(m_currentDir + "/" + directory); final String saveDir = m_currentDir; m_currentDir = m_currentDir + "/" + directory.getName(); directory.forEach(entry -> entry.accept(this)); m_currentDir = saveDir; } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
public class Main { public static void main(String[] args) { System.out.println("Making root entries..."); final Directory rootdir = new Directory("root"); final Directory bindir = new Directory("bin"); final Directory userdir = new Directory("user"); rootdir.add(bindir); rootdir.add(userdir); bindir.add(new File("vi",10000)); bindir.add(new File("latex",20000)); rootdir.accept(new ListVisitor()); System.out.println(); } } |
1 2 3 4 5 6 |
Making root entries... /root(30000) /root/bin(30000) /root/bin/vi(10000) /root/bin/latex(20000) /root/user(0) |