简介
访问者模式(VisitorPattern),顾名思义使用了这个模式后就可以在不修改已有程序结构的前提下,通过添加额外的访问者来完成对已有代码功能的提升,它属于行为模式。访问者模式的目的是封装一些施加于某种数据结构元素之上的操作。一旦这些操作需要修改的话,接受这个操作的数据结构则可以保持不变。
其主要目的是将数据结构与数据操作分离。
访问者模式可以说是设计模式中最难以理解的一个模式,因为相比其它模式而言,它过于”绕“了。但是我们可以通过生活中的一些例子来理解它,比如家里来了客人,客人就是访问者,他可以做一些事情,但是又不能做全部的事情; 又或者说去网吧上网的小明,小明也是访问者,他可以在网吧玩游戏、看视频、听音乐等等,但是不能破坏网吧中的设备等等。按照这么理解,我们大概就可以知道访问者模式主要是做什么了。
访问者模式主要由这五个角色组成,抽象访问者(Visitor)、具体访问者(ConcreteVisitor)、抽象节点(Node)、具体节点(ConcreteNode)和结构对象(ObjectStructure)。
抽象访问者(Visitor)角色:声明了一个或者多个方法操作,形成所有的具体访问者角色必须实现的接口。
具体访问者(ConcreteVisitor)角色:实现抽象访问者所声明的接口,也就是抽象访问者所声明的各个访问操作。
抽象节点(Node)角色:声明一个接受操作,接受一个访问者对象作为一个参数。
具体节点(ConcreteNode)角色:实现了抽象节点所规定的接受操作。
结构对象(ObjectStructure)角色:有如下的责任,可以遍历结构中的所有元素。
示例图如下:
这里为了方便理解,我们使用一个简单的示例来加以说明。
图书馆有一台电脑,有两个账户,其中一个是管理员的账户,拥有所有权限,但是设置了密码;另一个账户是不需要密码,但是只能玩游戏和看图片。张三和李四先后使用了这台电脑,那么他们就可以当作是访问者。
那么我们便可以根据这里例子来使用访问者模式进行开发,首先定义一个抽象的访问者,拥有玩游戏和看图片的方法;然后再定义一个抽象节点电脑,接受这个请求。
那么这个抽象类的代码如下:
interface Visitor {
void visit(Games games);
void visit(Photos photos);
}
interface Computer {
void accept(Visitor visitor);
}
定义好该抽象类之后,我们需要设计不同的访问者对节点进行不同的处理。并且需要设计具体节点类实现刚刚抽象节点的方法。
那么代码如下:
class ZhangSan implements Visitor {
@Override
public void visit(Games games) {
games.play();
}
@Override
public void visit(Photos photos) {
photos.watch();
}
}
class LiSi implements Visitor {
@Override
public void visit(Games games) {
games.play();
}
@Override
public void visit(Photos photos) {
photos.watch();
}
}
class Games implements Computer {
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
public void play() {
System.out.println("play lol");
}
}
class Photos implements Computer {
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
public void watch() {
System.out.println("watch scenery photo");
}
}
最后我们还需要定义一个结构对象角色,提供一个的接口并允许该访问者进行访问,它可以对这些角色进行增加、修改或删除等操作和遍历。
代码如下:
class ObjectStructure {
private List<Computer> computers = new ArrayList<Computer>();
public void action(Visitor visitor) {
computers.forEach(c -> {
c.accept(visitor);
});
}
public void add(Computer computer) {
computers.add(computer);
}
}
编写好之后,那么我们来进行测试。
测试代码如下:
public static void main(String[] args) {
// 创建一个结构对象
ObjectStructure os = new ObjectStructure();
// 给结构增加一个节点
os.add(new Games());
// 给结构增加一个节点
os.add(new Photos());
// 创建一个访问者
Visitor visitor = new ZhangSan();
os.action(visitor);
}
输出结果:
play lol
watch scenery photo
访问者模式优点:
扩展性好,可以在不修改对象结构中的元素的情况下,为对象结构中的元素添加新的功能;
符合单一职责原则,通过访问者将无关的行为分离,使职责单一;
访问者模式缺点:
违反了迪米特原则,因为具体元素对访问者公布细节;
违反了依赖倒置原则,依赖了具体类,没有依赖抽象;
对象结构变化困难,若对象结构发生了改变,访问者的接口和访问者的实现也都要发生相应的改变;
使用场景:
对象结构中对象对应的类很少改变,但经常需要在此对象结构上定义新的操作;
需要对一个对象结构中的对象进行很多不同的并且不相关的操作,而需要避免让这些操作"污染"这些对象的类,也不希望在增加新操作时修改这些类。
原文出处:
原文链接:https://blog.csdn.net/qazwsxpcm/article/details/83588888
来源:oschina
链接:https://my.oschina.net/u/4439464/blog/3157910