Visitor Pattern

Post on 01-Jan-2016

26 views 0 download

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 Presentation

Transcript of Visitor Pattern

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 側に必要になる。