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