概述
设计模式学习笔记——访问者(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)模式所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复