一、定义
访问者模式的英文翻译是 Visitor Design Pattern。在 GoF 的《设计模式》一书中,它 是这么定义的:
Allows for one or more operation to be applied to a set of objects at runtime, decoupling the operations from the object structure
允许一个或者多个操作应用到一组对象上,解耦操作和对象本身。就是将操作方式的扩展与操作的目标对象的扩展分离开,互不影响,所以,比如需要使用组合的方式。
二、类图关系
这个关系图与《桥接模式》很类似,但是使用场景不同:桥接模式是将抽象与实现进行解耦,而访问者是将操作行为与操作对象进行解耦。
三、案例
场景描述:对传入的编码文件进行压缩和加密处理。
① 创建访问者接口,注意,接口实际操作的对象是具体实现类
,也就是说,访问者模式为了实现拓展的灵活和单一职责而违背了迪米特法则和依赖倒置原则
/**
* 访问者接口:内部集成对编码的操作
*/
public interface Visitor {
/**
* 提供两个重载方法:分别处理UTF-8文件和GBK文件
*/
void executeUTF8File(UTF8EncodeFile utf8EncodeFile);
void executeGBKFile(GBKEncodeFile gbkEncodeFile);
}
/**
* 压缩文件处理
*/
@Slf4j
public class Compressor implements Visitor {
@Override
public void executeUTF8File(UTF8EncodeFile utf8EncodeFile) {
log.info("压缩UTF-8文件!");
}
@Override
public void executeGBKFile(GBKEncodeFile gbkEncodeFile) {
log.info("压缩GBK文件!");
}
}
/**
* 加密文件
*/
@Slf4j
public class Encryptor implements Visitor {
@Override
public void executeUTF8File(UTF8EncodeFile utf8EncodeFile) {
log.info("加密UTF-8文件……");
}
@Override
public void executeGBKFile(GBKEncodeFile gbkEncodeFile) {
log.info("加密GBK文件……");
}
}
② 创建目标对象抽象类——编码文件
/**
* 需要编码的文件
*/
public abstract class EncodingFile {
/**
* 抽象方法,对编码进行操作,将访问者传入
*/
public abstract void accept(Visitor visitor);
}
/**
* GBK编码文件
*/
public class GBKEncodeFile extends EncodingFile {
@Override
public void accept(Visitor visitor) {
visitor.executeGBKFile(this);
}
}
/**
* UTF-8格式文件
*/
public class UTF8EncodeFile extends EncodingFile {
/**
* 执行文件
*/
@Override
public void accept(Visitor visitor) {
visitor.executeUTF8File(this);
}
}
③ 测试
/**
* 访问者模式测试
*/
@RunWith(JUnit4.class)
public class VisitorTest {
/**
* 测试压缩和加密文件
*/
@Test
public void testCompressAndEncry() {
//创建压缩文件访问者
Compressor compressor = new Compressor();
//获取文件并循环压缩处理
createFile().forEach(e -> e.accept(compressor));
//创建加密文件者
Encryptor encryptor = new Encryptor();
//获取文件并循环加密
createFile().forEach(e -> e.accept(encryptor));
}
/**
* 创建文件
*/
private List<EncodingFile> createFile() {
return Lists.newArrayList(
new GBKEncodeFile(),
new UTF8EncodeFile()
);
}
}
[main] INFO c.j.s.v.i.Compressor - 压缩GBK文件!
[main] INFO c.j.s.v.i.Compressor - 压缩UTF-8文件!
[main] INFO c.j.s.v.i.Encryptor - 加密GBK文件……
[main] INFO c.j.s.v.i.Encryptor - 加密UTF-8文件……