概念
封装某些作用于某种数据结构中各元素的操作,它可以在不改变数据结构的前提下定义作用于这些元素的新的操作。
角色
先上一张图:
![](https://img.haomeiwen.com/i2064937/f9dca934c6ef6b63.jpg)
抽象访问者:抽象类或者接口,声明访问者可以访问哪些元素
访问者:实现抽象访问者所声明的方法,它影响到访问者访问到一个类后该干什么,要做什么事情。
抽象元素类:接口或者抽象类,声明接受哪一类访问者访问。
元素类:实现抽象元素类所声明的方法。
结构对象:一个元素的容器,一般包含一个容纳多个不同类、不同接口的容器,如List、Set、Map等。
上代码
就模拟一下文件访问操作。
抽象访问者
/**
*
* 抽象访问者类:申明可以访问哪些元素
*
*/
public interface Visiter {
void visit(DocA doca);
void Visit(DocB docb);
}
访问者
/**
* 具体的访问者
*
*/
public class VisiterA implements Visiter {
@Override
public void visit(DocA doca) {
System.out.println("DocA's content is:" + doca.readDoc());
}
@Override
public void Visit(DocB docb) {
System.out.println("DocB's content is:" + docb.readDoc());
}
}
抽象元素类
/**
*
* 抽象元素类:声明 接受何种类型的访问。
*
*/
public abstract class Doc {
public abstract void accept(Visiter visiter);
public abstract String readDoc();
}
具体的元素类
这里可以把readDoc方法交由Visiter实现。
/**
*
* 具体的元素类A(ConcreteElement)
*
*/
public class DocA extends Doc {
//使用accept,代表只有指定的visiter才能访问。
@Override
public void accept(Visiter visiter) {
visiter.visit(this);
}
@Override
public String readDoc() {
return "This is DocA";
}
}
/**
* 具体的元素类B(ConcreteElement)
*
*/
public class DocB extends Doc{
@Override
public void accept(Visiter visiter) {
visiter.Visit(this);
}
@Override
public String readDoc() {
return "This is DocB";
}
}
结构对象
/**
*
*文件袋:结构对象,容纳元素
*/
public class DocBag {
private List<Doc> docs = new ArrayList<>();
public List<Doc> getList(){
if(docs.size()==0){
docs.add(new DocA());
docs.add(new DocB());
}
return docs;
}
}
客户端测试类
public class VisitClient {
public static void main(String[] args) {
DocBag bags = new DocBag();
List<Doc> docs = bags.getList();
VisiterA visiter = new VisiterA();
for(Doc doc:docs){
doc.accept(visiter);
}
}
}
![](https://img.haomeiwen.com/i2064937/e4defb5d6947a780.png)
The End
看完代码就发现了,访问者模式主要将数据结构与数据操作分离。但是这样不符合迪米特原则。
优点:
1、可扩展性比较好,灵活。元素类可以通过接受不同的访问者来实现对不同操作的扩展。
2、符合单一职责原则。
缺点:
1、具体元素对访问者公布细节,违反了迪米特原则。
2、因为访问者对应着具体元素的操作,所以添加元素的话需要修改很多地方。
网友评论