一、基本介绍
访问者模式(行为型):将数据操作和数据结构分离的设计模式,即不直接去操作数据,通过中间一个数据结构去操作数据。
二、包含角色
1.抽象访问者:定义一个访问具体元素的接口,为每个具体元素类对应一个访问操作 ,该操作中的参数类型标识了被访问的具体元素。
2.具体访问者:实现抽象访问者角色中声明的各个访问操作,确定访问者访问每一个具体元素该进行什么样的操作。
3.抽象元素角色:声明一个包含接受操作 accept() 的接口,访问者对象作为 accept() 方法的参数。
4.具体元素角色:实现抽象元素角色提供的 accept() 操作,接收一个访问者对象,并回调访问者的具体访问方法。
5.对象结构角色:是一个包含具体元素角色的容器,提供让访问者对象遍历容器中的所有具体元素角色的方法,通常由 List、Set、Map 等聚合类实现。
三、案例及UML类图
案例说明:
2020年是脱贫攻坚的最后一年,官员要具体去走访贫困家庭和低保户家庭,官员可能是村长,村委会主席、县长等,官员不确定,但走访的对象是确定的。
UML类图:
类Official:
public interface Official {
void visitPoorFamilies(PoorFamilies poorFamilies);
void visitLowInsuredFamilies(LowInsuredFamilies lowInsuredFamilies);
}
说明:官员接口,抽象访问者,定义每个官员走访的对象和接口。
类VillageHead:
public class VillageHead implements Official {
@Override
public void visitPoorFamilies(PoorFamilies poorFamilies) {
System.out.println("村长带领"+poorFamilies.getName()+"脱贫!");
}
@Override
public void visitLowInsuredFamilies(LowInsuredFamilies lowInsuredFamilies) {
System.out.println("村长带领"+lowInsuredFamilies.getName()+"脱贫!");
}
}
说明:村长类,具体访问者,实现各个访问操作,并且确定村长访问这些对象要进行什么样的操作。
类OvercomePovertyFamily:
public interface OvercomePovertyFamily {
void accept(Official official);
}
说明:脱贫家庭接口,抽象元素角色,被访问需要脱贫的家庭接口定义,接收一个官员的访问。
类LowInsuredFamilies:
public class LowInsuredFamilies implements OvercomePovertyFamily {
private String name = "低保户";
@Override
public void accept(Official official) {
official.visitLowInsuredFamilies(this);
}
public String getName() {
return name;
}
}
说明:低保户家庭,具体元素角色,实现抽象元素角色的方法,并且当访问者(官员)到来时,调用访问者(官员)的访问低保户方法。
类PoorFamilies:
public class PoorFamilies implements OvercomePovertyFamily {
private String name = "贫困家庭";
@Override
public void accept(Official official) {
official.visitPoorFamilies(this);
}
public String getName() {
return name;
}
}
说明:贫困家庭,具体元素角色,实现抽象元素角色的方法,并且当访问者(官员)到来时,调用访问者(官员)的访问贫困户方法。
类ObjectStructure:
public class ObjectStructure {
//需要访问的元素,即被访问元素
private List<OvercomePovertyFamily> overcomePovertyFamilies = new ArrayList<>();
/**
* 添加一个被访问的元素
* @param overcomePovertyFamily 需要脱贫的家庭
*/
public void attach(OvercomePovertyFamily overcomePovertyFamily){
overcomePovertyFamilies.add(overcomePovertyFamily);
}
/**
* 官员开始走访
* @param official 官员
*/
public void visit(Official official) {
for(OvercomePovertyFamily o : overcomePovertyFamilies) {
o.accept(official);
}
}
}
说明:对象结构类,对象结构角色,添加被访问者和调用访问操作,隔离访问者和被访问者。
类VisitorTest:
public class VisitorTest {
public static void main(String[] args) {
//贫困家庭
OvercomePovertyFamily o1 = new PoorFamilies();
//低保户
OvercomePovertyFamily o2 = new LowInsuredFamilies();
//结构对象,存储被访问者
ObjectStructure objectStructure = new ObjectStructure();
objectStructure.attach(o1);
objectStructure.attach(o2);
//官员,村长
Official villageHead = new VillageHead();
//村长走访
objectStructure.visit(villageHead);
}
}
说明:测试及客户端类。
五、优缺点
优:
1.符合单一职责原则。访问者模式把相关的行为封装在一起,构成一个访问者,使每一个访问者的功能都比较单一。
2.对于访问者来说,是符合开闭原则的,是可以拓展的。
缺:
1.类比较多,增加了代码的复杂度。
2.对于被访问者来说,是不符合开闭原则的,每增加一个被访问者,则访问者就需要添加新的方法去进行操作。
六、适用场景
1.操作对象(被访问者)结构相对稳定,但其操作算法(访问者)经常变化的程序。
2.对象结构中的对象需要提供多种不同且不相关的操作,而且要避免让这些操作的变化影响对象的结构。