访问者模式
访问者模式属于行为型模式。它是一种将数据结构与数据操作分离的设计模式。是指封装一些作用于某种数据结构中的各元素的操作,它可以在不改变数据结构的前提下定义作用于这些元素的新的操作。
访问者模式被称为最复杂的设计模式,使用频率不高。
访问者模式最大的优点就是增加访问者非常容易,如果要增加一个访问者,只要新实现一个访问者接口的类,从而达到数据对象与数据操作相分离的效果。
应用
1.数据结构稳定,作用于数据结构的操作经常变化的场景
2.需要数据结构与数据操作分离的场景
3.需要对不同数据类型(元素)进行操作,而不使用分支判断具体类型的场景
举例:饭馆吃饭,饭馆菜品相对固定,但每天去吃饭的人是变化的,人即访问者。
主要角色
1.抽象访问者(Visitor)
接口或抽象类,定义了对每一个具体元素(Element)的访问行为visit()方法,其参数就是具体的元素(Element)对象
通常来说:Visitor的方法个数与元素(Element)个数是相等的。如果元素(Element)个数经常变动,会导致Visitor的方法也要进行变动
2.具体访问者(ConcreteVisitor)
实现对具体元素的操作
3.抽象元素(Element)
接口或抽象类,定义了一个接受访问者访问的方法accept(),表示所有元素类型都支持被访问者访问
4.具体元素(Concrete Element)
具体元素类型,提供接受访问者的具体实现。通常的实现都为:visitor.visit(this)
5.结构对象(ObjectStruture)
该类内部维护了元素集合,并提供方法接受访问者对该集合所有元素进行操作
优缺点
优点:
1.解耦了数据结构与数据操作,使得操作集合可以独立变化
2.扩展性好:可以通过扩展访问者角色,实现对数据集的不同操作
3.元素具体类型并非单一,访问者均可操作
4.心各角色职责分离,符合单一职责原侧出前
缺点:
1.无法增加元素类型:若系统数据结构对象易于变化,经常有新的数据对象增加进来,则访问者类必须增加对应元素类型的操作,违背开闭原则
2.具体元素变更困难:具体元素增加属性,删除属性等操作会导致对应的访问者类需要进行相应的修改,尤其当有大量访问者类时,修改范围太大
3.违背依赖倒置原则:访问者依赖的是具体元素类型,而不是抽象。
基本使用
创建抽象访问者
public interface IVisitor {
void visit(ConcreteElementA element);
void visit(ConcreteElementB element);
}
创建具体访问者
public class ConcreteVisitorA implements IVisitor {
public void visit(ConcreteElementA element) {
String result = element.get();
System.out.println("具体访问者ConcreteVisitorA,访问结果: " + result);
}
public void visit(ConcreteElementB element) {
String result = element.get();
System.out.println("具体访问者ConcreteVisitorA,访问结果: " + result);
}
}
public class ConcreteVisitorB implements IVisitor {
public void visit(ConcreteElementA element) {
String result = element.get();
System.out.println("具体访问者ConcreteVisitorB,访问结果: " + result);
}
public void visit(ConcreteElementB element) {
String result = element.get();
System.out.println("具体访问者ConcreteVisitorB,访问结果: " + result);
}
}
创建抽象元素
public interface IElement {
void accept(IVisitor visitor);
}
创建具体元素
public class ConcreteElementA implements IElement {
public void accept(IVisitor visitor) {
visitor.visit(this);
}
public String get() {
return "我是具体元素ConcreteElementA";
}
}
public class ConcreteElementB implements IElement {
public void accept(IVisitor visitor) {
visitor.visit(this);
}
public String get() {
return "我是具体元素ConcreteElementB";
}
}
创建结构对象
public class ObjectStructure {
private List<IElement> list = new ArrayList<IElement>();
{
this.list.add(new ConcreteElementA());
this.list.add(new ConcreteElementB());
}
public void accept(IVisitor visitor) {
for (IElement element : this.list) {
element.accept(visitor);
}
}
}
客户端执行
public static void main(String[] args) {
// 结构对象
ObjectStructure collection = new ObjectStructure();
// 访问者A
IVisitor visitorA = new ConcreteVisitorA();
collection.accept(visitorA);
System.out.println("------------------------------------");
// 访问者B
IVisitor visitorB = new ConcreteVisitorB();
collection.accept(visitorB);
}
具体访问者ConcreteVisitorA,访问结果: 我是具体元素ConcreteElementA
具体访问者ConcreteVisitorA,访问结果: 我是具体元素ConcreteElementB
------------------------------------
具体访问者ConcreteVisitorB,访问结果: 我是具体元素ConcreteElementA
具体访问者ConcreteVisitorB,访问结果: 我是具体元素ConcreteElementB