访问者模式(Visitor),是行为模式之一,它分离对象的数据和行为,使用Visitor模式,可以不修改已有类的情况下,增加新的操作。根据模式,元素对象已接受访问者对象,这样访问者对象就可以处理元素对象上的操作。
解决问题:
稳定的数据结构和易变的操作耦合问题。
访问者可以对功能进行统一,可以做报表、UI、拦截器与过滤器。
使用场景:
(1)对象结构比较稳定,但经常需要在此对象结构上定义新的操作。
(2)需要对一个对象结构中的对象进行很多不同的且不相关的操作,而需要避免这些操作“污染”这些对象的类,也不希望在增加新操作时修改这些类。
访问者模式的UML图:
角色和职责:
1) 访问者角色(Visitor):为该对象结构中具体元素角色声明一个访问操作接口或抽象类。该操作接口的名字和参数标识了发送访问请求给具体访问者的具体元素角色。这样访问者就可以通过该元素角色的特定接口直接访问它。
2) 具体访问者角色(ConcreteVisitor):实现每个由访问者角色(Visitor)声明的操作的具体行为。
3) 元素角色(Element):元素接口或者抽象类,它定义了一个接受访问者的方法(Accept),其意义是指每一个元素都要可以被访问者访问。
4) 具体元素角色(ConcreteElement):具体的元素类,它提供接受访问方法的具体实现,而这个具体的实现,通常情况下是使用访问者提供的访问该元素类的方法。
5) 对象结构角色(ObjectStructure):这是使用访问者模式必备的角色。它要具备以下特征:能枚举它的元素;可以提供一个高层的接口以允许该访问者访问它的元素;可以是一个复合(组合模式)或是一个集合,如一个列表或一个无序
集合。代码示例:
/**
* 公园每一部分的抽象
*/
public interface ParkElement {
//用来接纳访问者
public void accept(Visitor visitor);
}
/**
* 公园的A部分
*/
public class ParkA implements ParkElement {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void accept(Visitor visitor) {
visitor.visit(this);
}
}
/**
* 公园的B部分
*/
public class ParkB implements ParkElement {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void accept(Visitor visitor) {
visitor.visit(this);
}
}
/**
* 公园
*/
public class Park implements ParkElement {
private String name;
private ParkA parkA;
private ParkB parkB;
public Park(){
this.parkA = new ParkA();
this.parkB = new ParkB();
parkA.setName("A");
parkB.setName("B");
}
public void accept(Visitor visitor) {
visitor.visit(this);
parkA.accept(visitor);
parkB.accept(visitor);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
/**
* 访问者
*/
public interface Visitor {
public void visit(Park park);
public void visit(ParkA parkA);
public void visit(ParkB parkB);
}
/**
* 清洁工A,负责parkA的卫生情况
*/
public class VisitorA implements Visitor {
public void visit(Park park) {
}
public void visit(ParkA parkA) {
System.out.println("清洁工A:完成公园" + parkA.getName()+ "的卫生");
}
public void visit(ParkB parkB) {
}
}
/**
* 清洁工B,负责parkB的卫生情况
*/
public class VisitorB implements Visitor {
public void visit(Park park) {
}
public void visit(ParkA parkA) {
}
public void visit(ParkB parkB) {
System.out.println("清洁工b:完成公园" + parkB.getName()+ "的卫生");
}
}
/**
* @author 833902
* 2018年4月7日 下午1:55:31
*/
public class VisitorManager implements Visitor {
public void visit(Park park) {
System.out.println("管理员:负责" + park.getName() + "卫生检查");
}
public void visit(ParkA parkA) {
System.out.println("管理员:负责公园"+ parkA.getName() +"部分卫生检查");
}
public void visit(ParkB parkB) {
System.out.println("管理员:负责公园"+ parkB.getName() +"分部卫生检查");
}
}
public class MainClass {
public static void main(String[] args) {
Park park = new Park();
park.setName("中山公园");
VisitorA visitorA = new VisitorA();
park.accept(visitorA);
VisitorB visitorB = new VisitorB();
park.accept(visitorB);
VisitorManager visitorManager = new VisitorManager();
park.accept(visitorManager);
}
}
优点:
1、符合单一职责原则。 2、优秀的扩展性。 3、灵活性。
缺点:
1、具体元素对访问者公布细节,违反了迪米特原则。
2、具体元素变更比较困难。
3、违反了依赖倒置原则,依赖了具体类,没有依赖抽象。