设计模式学习笔记——访问者(Visitor)模式
@(设计模式)[设计模式, 访问者模式, visitor]
- 设计模式学习笔记访问者Visitor模式
- 基本介绍
- 访问者案例
- 类图
- 实现代码
- Visitor抽象类
- ListVisitor类
- Element接口
- Entry抽象类
- File类
- Directory类
- FileTreatmentException类
- 测试类
- 运行结果
- 访问者模式中的角色
- Visitor访问者
- ConcreteVisitor具体的访问者
- Element元素
- ConcreteElement
- ObjectStructure对象结构
- 类图
基本介绍
访问者模式主要的作用是对对象中元素进行操作。
使用访问者模式,在更改对元素的操作时,不需要更改类的定义。
访问者案例
类图

实现代码
Visitor抽象类
package com.pc.visitor.example;
/**
* 访问者抽象类
* Created by Switch on 2017-02-22.
*/
public abstract class Visitor {
/**
* 访问文件
*
* @param file 文件对象
*/
public abstract void visit(File file);
/**
* 访问文件夹
*
* @param directory 文件夹对象
*/
public abstract void visit(Directory directory);
}
ListVisitor类
package com.pc.visitor.example;
import java.util.Iterator;
/**
* 列表访问类
* Created by Switch on 2017-02-22.
*/
public class ListVisitor extends Visitor {
/**
* 当前访问的文件夹的名字
*/
private String currentDir = "";
@Override
public void visit(File file) {
System.out.println(this.currentDir + "/" + file);
}
@Override
public void visit(Directory directory) {
System.out.println(currentDir + "/" + directory);
// 递归调用,回溯法
String saveDir = this.currentDir;
this.currentDir = this.currentDir + "/" + directory.getName();
Iterator<Entry> iterator = directory.iterator();
while (iterator.hasNext()) {
Entry entry = iterator.next();
entry.accept(this);
}
this.currentDir = saveDir;
}
}
Element接口
package com.pc.visitor.example;
/**
* 元素接口(代表可以接受访问)
* Created by Switch on 2017-02-22.
*/
public interface Element {
/**
* 接受访问者对象访问
*
* @param visitor 访问者对象
*/
void accept(Visitor visitor);
}
Entry抽象类
package com.pc.visitor.example;
/**
* 条目抽象类
* Created by Switch on 2017-02-21.
*/
public abstract class Entry implements Element {
/**
* 获取名字
*
* @return 名字
*/
public abstract String getName();
/**
* 获取占用空间
*
* @return 占用空间
*/
public abstract int getSize();
/**
* 添加
*
* @param entry 条目对象
* @return 返回文件夹对象
* @throws FileTreatmentException 文件处理异常
*/
public Entry add(Entry entry) throws FileTreatmentException {
throw new FileTreatmentException("只有文件夹才能添加条目!");
}
/**
* 使用默认前缀,显示目录条目
*/
public void printList() {
printList("");
}
/**
* 指定前缀,显示目录条目
*
* @param prefix 前缀
*/
protected abstract void printList(String prefix);
@Override
public String toString() {
return this.getName() + " (" + this.getSize() + ")";
}
}
File类
package com.pc.visitor.example;
/**
* 文件类
* Created by Switch on 2017-02-21.
*/
public class File extends Entry {
/**
* 文件名
*/
private String name;
/**
* 文件占用空间
*/
private int size;
/**
* 构造方法,传入文件名和文件占用空间
*
* @param name 文件名
* @param size 文件占用空间
*/
public File(String name, int size) {
this.name = name;
this.size = size;
}
@Override
public String getName() {
return this.name;
}
@Override
public int getSize() {
return this.size;
}
@Override
protected void printList(String prefix) {
System.out.println(prefix + "/" + this);
}
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
}
Directory类
package com.pc.visitor.example;
import com.pc.abstractfactory.example.factory.Item;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
/**
* 文件夹类
* Created by Switch on 2017-02-21.
*/
public class Directory extends Entry {
/**
* 文件夹名
*/
private String name;
/**
* 文件夹中的条目集合
*/
private List<Entry> entries = new ArrayList<>();
/**
* 构造方法,传入文件夹名
*
* @param name 文件夹名
*/
public Directory(String name) {
this.name = name;
}
@Override
public String getName() {
return this.name;
}
@Override
public int getSize() {
int size = 0;
for (Entry entry : entries) {
size += entry.getSize();
}
return size;
}
@Override
public Entry add(Entry entry) {
this.entries.add(entry);
return this;
}
@Override
protected void printList(String prefix) {
System.out.println(prefix + "/" + this);
for (Entry entry : entries) {
// 打印文件夹下的文件列表,以文件夹前缀,文件名作为前缀
entry.printList(prefix + "/" + this.name);
}
}
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
/**
* 获取迭代器
*
* @return 迭代器
*/
public Iterator<Entry> iterator() {
return this.entries.iterator();
}
}
FileTreatmentException类
package com.pc.visitor.example;
/**
* 文件处理异常
* Created by Switch on 2017-02-21.
*/
public class FileTreatmentException extends RuntimeException {
public FileTreatmentException() {
}
public FileTreatmentException(String message) {
super(message);
}
}
测试类
package com.pc.visitor.example.test;
import com.pc.visitor.example.Directory;
import com.pc.visitor.example.File;
import com.pc.visitor.example.FileTreatmentException;
import com.pc.visitor.example.ListVisitor;
import org.junit.Test;
/**
* Visitor Tester.
*
* @author Switch
* @version 1.0
*/
public class VisitorTest {
/**
* 测试访问者模式
*/
@Test
public void testVisitor() {
try {
System.out.println("添加文件和文件夹:");
System.out.println("Making root entries...");
Directory rootDir = new Directory("root");
Directory binDir = new Directory("bin");
Directory usrDir = new Directory("usr");
rootDir.add(binDir);
rootDir.add(usrDir);
binDir.add(new File("java", 5000));
binDir.add(new File("javac", 10000));
rootDir.accept(new ListVisitor());
System.out.println();
System.out.println("接着添加文件和文件夹:");
System.out.println("Making user entries...");
Directory switchvov = new Directory("switchvov");
Directory kity = new Directory("kity");
Directory tom = new Directory("tom");
Directory bob = new Directory("bob");
usrDir.add(switchvov);
usrDir.add(kity);
usrDir.add(bob);
switchvov.add(new File("readme.txt", 1000));
switchvov.add(new File("hello.txt", 400));
kity.add(new File("find.sh", 5000));
rootDir.accept(new ListVisitor());
} catch (FileTreatmentException e) {
e.printStackTrace();
}
}
}
运行结果
添加文件和文件夹:
Making root entries...
/root (15000)
/root/bin (15000)
/root/bin/java (5000)
/root/bin/javac (10000)
/root/usr (0)
接着添加文件和文件夹:
Making user entries...
/root (21400)
/root/bin (15000)
/root/bin/java (5000)
/root/bin/javac (10000)
/root/usr (6400)
/root/usr/switchvov (1400)
/root/usr/switchvov/readme.txt (1000)
/root/usr/switchvov/hello.txt (400)
/root/usr/kity (5000)
/root/usr/kity/find.sh (5000)
/root/usr/bob (0)
访问者模式中的角色
Visitor(访问者)
Visitor角色负责对数据结构中每个具体的元素(ConcreteElement角色)声明一个用于访问xxxxx的visit(XXXXX)方法。visit(XXXXX)是用于处理xxxxx的方法,负责实现该方法的是ConcreteVisitor角色。在案例中,由Visitor类扮演此角色。
ConcreteVisitor(具体的访问者)
ConcreteVisitor角色负责实现Visitor角色所定义的接口(API )。它要实现所有的visit(XXXXX)方法,即实现如何处理每个ConcreteElement角色。在案例中,由ListVisitor类扮演此角色。如同在ListVisitor中, currentdir字段的值不断发生变化一样,随着visit(XXXXX)处理的进行,ConcreteVisitor角色的内部状态也会不断地发生变化。
Element(元素)
Element角色表示Visitor角色的访问对象。它声明了接受访问者的accept方法。accept方法接收到的参数是Visitor角色。在案例中,由Element接口扮演此角色。
ConcreteElement
ConcreteElement角色负责实现Element角色所定义的接口(API)。在案例中,由File类和Directory类扮演此角色。
ObjectStructure(对象结构)
ObjectStructur角色负责处理Element角色的集合。ConcreteVisitor角色为每个Element角色都准备了处理方法。在案例中,由Directory类扮演此角色( 一人分饰两角)。为了让ConcreteVisitor角色可以遍历处理每个Element 角色,在案例中,我们在Directory类中实现了iterator方法。
类图

GitHub:DesignPatternStudy
——————参考《图解设计模式》
最后
以上就是魁梧黑夜最近收集整理的关于设计模式学习笔记——访问者(Visitor)模式设计模式学习笔记——访问者(Visitor)模式的全部内容,更多相关设计模式学习笔记——访问者(Visitor)模式设计模式学习笔记——访问者(Visitor)模式内容请搜索靠谱客的其他文章。
发表评论 取消回复