Visitor Pattern http://www.k.hosei.ac.jp/~yukita/ Visitor Pattern の目的 • データ構造と処理の分離 Visitor Pattern 2 Visitor visit(File) visit(Directory) ListVisitor 例題のクラス図 <<interface>> Acceptor accept Entry currentdir visit(File) visit(Directory) Uses Main getName getSize add iterator File Directory name size name dir accept getName getSize Uses accept getName getSize add iterator Uses Visitor Pattern 3 Visitor.java public abstract class Visitor { public abstract void visit(File file); public abstract void visit(Directory directory); } Visitor Pattern 4 Acceptor.java public interface Acceptor { public abstract void accept(Visitor v); } Visitor Pattern 5 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 6 Entry.java (2) public Iterator iterator() throws FileTreatmentException { throw new FileTreatmentException(); } public String toString() { return getName() + " (" + getSize() + ")"; } } Visitor Pattern 7 Entry におけるダミー実装 • add, iterator メソッドは File ではエラーとな る。 • add, iterator メソッドは Directory で意味を もつ。 Visitor Pattern 8 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 9 File.java (2) public int getSize() { return size; } public void accept(Visitor v) { v.visit(this); } } Visitor Pattern 10 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 11 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 } 12 Directory.java (3) public Iterator iterator() { return dir.iterator(); } public void accept(Visitor v) { v.visit(this); } } Visitor Pattern 13 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 14 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 15 Visitorが処理を担当 • Visitor インタフェースを実装している ListVisitor が処理を担当する。 • 一方,Acceptor 側の File, Directory は処 理を担わず,データの保持だけに責任をも つ。 Visitor Pattern 16 FileTreatmentException.java public class FileTreatmentException extends RuntimeException { public FileTreatmentException() { } public FileTreatmentException(String msg) { super(msg); } } Visitor Pattern 17 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 18 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 19 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 20 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 21 実行結果 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 22 Sequence Diagram Main new :Directory :ListVisitor :File :File accept visit accept visit accept visit Visitor Pattern 23 パターン ObjectStructure Visitor Acceptor visit(ConcreteAcceptorA) visit(ConcreteAcceptorB) ConcreteVisitor visit(ConcreteAcceptorA) visit(ConcreteAcceptorB) accept ConcreteAcceptorA accept ConcreteAcceptorB accept Visitor Pattern 24 注意 • ConcreteVisitor の追加は簡単 – このときConcreteAcceptorの変更は不要 • ConcreteAcceptor の使いは困難 – 例えば Entry のサブクラス Device を追加しよ うとすれば Visit(Device)メソッドが Visitor側に 必要になる。 Visitor Pattern 25
© Copyright 2024 ExpyDoc