270 likes | 450 Views
Visitor Pattern. http://www.k.hosei.ac.jp/~yukita/. Visitor Pattern の目的. データ構造と処理の分離. 例題のクラス図. Uses. Uses. Uses. Visitor.java. public abstract class Visitor { public abstract void visit(File file); public abstract void visit(Directory directory); }. Acceptor.java.
E N D
Visitor Pattern http://www.k.hosei.ac.jp/~yukita/
Visitor Pattern の目的 • データ構造と処理の分離 Visitor Pattern
例題のクラス図 Uses Uses Uses Visitor Pattern
Visitor.java public abstract class Visitor { public abstract void visit(File file); public abstract void visit(Directory directory); } Visitor Pattern
Acceptor.java public interface Acceptor { public abstract void accept(Visitor v); } Visitor Pattern
Entry.java (1) import java.util.Iterator; public abstract class Entry implements Acceptor { public abstract String getName(); public abstract int getSize(); public Entry add(Entry entry) throws FileTreatmentException { throw new FileTreatmentException(); } Visitor Pattern
Entry.java (2) public Iterator iterator() throws FileTreatmentException { throw new FileTreatmentException(); } public String toString() { return getName() + " (" + getSize() + ")"; } } Visitor Pattern
Entry におけるダミー実装 • add, iterator メソッドは File ではエラーとなる。 • add, iterator メソッドは Directory で意味をもつ。 Visitor Pattern
File.java (1) 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; } Visitor Pattern
File.java (2) public int getSize() { return size; } public void accept(Visitor v) { v.visit(this); } } Visitor Pattern
Directory.java (1) import java.util.Iterator; import java.util.Vector; public class Directory extends Entry { private String name; private Vector dir = new Vector(); public Directory(String name) { this.name = name; } public String getName() { return name; } Visitor Pattern
Directory.java (2) public int getSize() { int size = 0; Iterator it = dir.iterator(); while (it.hasNext()) { Entry entry = (Entry)it.next(); size += entry.getSize(); } return size; } public Entry add(Entry entry) { dir.add(entry); return this; } Visitor Pattern
Directory.java (3) public Iterator iterator() { return dir.iterator(); } public void accept(Visitor v) { v.visit(this); } } Visitor Pattern
ListVisitor.java (1) import java.util.Iterator; public class ListVisitor extends Visitor { private String currentdir = ""; public void visit(File file) { System.out.println(currentdir + "/" + file); } Visitor Pattern
ListVisitor.java (2) public void visit(Directory directory) { System.out.println(currentdir + "/" + directory); String savedir = currentdir; currentdir = currentdir + "/" + directory.getName(); Iterator it = directory.iterator(); while (it.hasNext()) { Entry entry = (Entry)it.next(); entry.accept(this); } currentdir = savedir; } } Visitor Pattern
Visitorが処理を担当 • Visitor インタフェースを実装しているListVisitor が処理を担当する。 • 一方,Acceptor 側の File, Directory は処理を担わず,データの保持だけに責任をもつ。 Visitor Pattern
FileTreatmentException.java public class FileTreatmentException extends RuntimeException { public FileTreatmentException() { } public FileTreatmentException(String msg) { super(msg); } } Visitor Pattern
Main.java (1) 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"); Visitor Pattern
Main.java (2) 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 entries..."); Visitor Pattern
Main.java (3) 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)); Visitor Pattern
Main.java (4) 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 (FileTreatmentException e) { e.printStackTrace(); } } } Visitor Pattern
Making root entries... /root (30000) /root/bin (30000) /root/bin/vi (10000) /root/bin/latex (20000) /root/tmp (0) /root/usr (0) Making user entries... /root (31500) /root/bin (30000) /root/bin/vi (10000) /root/bin/latex (20000) /root/tmp (0) /root/usr (1500) /root/usr/yuki (300) /root/usr/yuki/diary.html (100) /root/usr/yuki/Composite.java (200) /root/usr/hanako (300) /root/usr/hanako/memo.tex (300) /root/usr/tomura (900) /root/usr/tomura/game.doc (400) /root/usr/tomura/junk.mail (500) 実行結果 Visitor Pattern
Main Sequence Diagram :Directory :File :File new :ListVisitor accept visit accept visit accept visit Visitor Pattern
パターン Visitor Pattern
注意 • ConcreteVisitor の追加は簡単 • このときConcreteAcceptorの変更は不要 • ConcreteAcceptor の使いは困難 • 例えば Entry のサブクラス Device を追加しようとすれば Visit(Device)メソッドが Visitor側に必要になる。 Visitor Pattern