定义:表示一个作用于某对象结构中的歌元素的操作,可以使你在不改变个元素的类的前提下定义作用于这些元素的操作。
当需要扩展一个已有类的层次结构时,我们一般只需要简单增加一些方法来扩展的行为,会出现已有对象和需要扩展的行为不一致的情况,这种情况下不修改层次结构中的类就无法扩展其行为。访问者模式可以解决这个问题。
1.Visitor 抽象访问者角色,为该对象结构中具体元素角色声明一个访问操作接口。该操作接口的名字和参数标识了发送访问请求给具体访问者的具体元素角色,这样访问者就可以通过该元素角色的特定接口直接访问它。
2.ConcreteVisitor.具体访问者角色,实现Visitor声明的接口,访问者访问到一个类后需要做什么。
3.Element 定义一个接受访问操作(accept()),它以一个访问者(Visitor)作为参数,接受哪一类型的访问者访问。
4.ConcreteElement 具体元素,实现了抽象元素(Element)所定义的接受操作接口,accept方法。
5.ObjectStructure 结构对象角色,这是使用访问者模式必备的角色,可以容纳多个不同的类,不同接口的容器。它具备以下特性:能枚举它的元素;可以提供一个高层接口以允许访问者访问它的元素;如有需要,可以设计成一个复合对象或者一个聚集(如一个列表或无序集合)。
基本代码:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
|
public abstract class Visitor {
public abstract void visitConcreteElementA(ConcreteElementA concreteElementA);
public abstract void visitConcreteElementB(ConcreteElementB concreteElementB);
}public class ConcreteVisitor extends Visitor {
@Override
public void visitConcreteElementA(ConcreteElementA concreteElementA) {
System.out.println(concreteElementA.getClass().getCanonicalName()+
"by"+this.getClass().getCanonicalName()+"visitor");
}
@Override
public void visitConcreteElementB(ConcreteElementB concreteElementB) {
System.out.println(concreteElementB.getClass().getCanonicalName()+
"by"+this.getClass().getCanonicalName()+"visitor");
}
}public abstract class Element {
public abstract void accept(Visitor visitor);
}public class ConcreteElementA extends Element {
//接受访问方法
@Override
public void accept(Visitor visitor) {
visitor.visitConcreteElementA(this);
}
//操作方法
public void operation(){
}
}public class ConcreteElementB extends Element{
@Override
public void accept(Visitor visitor) {
visitor.visitConcreteElementB(this);
}
public void operation(){
}
}public class ObjectStructure {
private List<Element> elements = new ArrayList<Element>();
public void attach(Element element){
elements.add(element);
}
public void detach(Element element){
elements.remove(element);
}
public void accept(Visitor visitor){
for (int i = 0; i < elements.size(); i++) {
(elements.get(i)).accept(visitor);
}
}
}public static void main(String[] args) {
ObjectStructure obS = new ObjectStructure();
obS.attach(new ConcreteElementA());
obS.attach(new ConcreteElementB());
ConcreteVisitor visitor = new ConcreteVisitor();
obS.accept(visitor);
}
|
举个例子:一个公司的领导要检查公司的工作情况,那么就一定要阅读相关报表,那么报表和领导之间是不是一个访问者模式的关系呢?
访问者模式把数据结构和作用于结构上的操作解耦合,使得操作集合可相对自由地演化。访问者模式适用于数据结构相对稳定算法又易变化的系统。因为访问者模式使得算法操作增加变得容易。若系统数据结构对象易于变化,经常有新的数据对象增加进来,则不适合使用访问者模式。访问者模式的优点是增加操作很容易,因为增加操作意味着增加新的访问者。访问者模式将有关行为集中到一个访问者对象中,其改变不影响系统数据结构。其缺点就是增加新的数据结构很困难。
抽象的领导类相当于抽象的访问者类:
|
1
2
3
4
|
public abstract class Leader {
public abstract void visitFinancialReport(FinancialReport financialReport);
public abstract void visitLogisticsReport(LogisticsReport logisticsReport);
} |
一个具体的访问者,财务总监:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
public class FinanceDirector extends Leader {
@Override
public void visitFinancialReport(FinancialReport financialReport) {
int income=financialReport.getIncome()-financialReport.getExpenditure();
System.out.println("总收入:"+income+"元");
}
@Override
public void visitLogisticsReport(LogisticsReport logisticsReport) {
//不关心销售报表
}
} |
另一个具体的访问者,销售总监:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
public class SalesDirector extends Leader {
@Override
public void visitFinancialReport(FinancialReport financialReport) {
//不关心财务报表
}
@Override
public void visitLogisticsReport(LogisticsReport logisticsReport) {
int stock = logisticsReport.getProduction()-logisticsReport.getSale();
System.out.println("当前库存为:"+stock+"件");
}
} |
财务报表了类:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
public abstract class Reporter {
public abstract void accept(Leader leader);
}public class FinancialReport extends Reporter{
private int income = 1000;
private int expenditure = 500;
@Override
public void accept(Leader leader) {
leader.visitFinancialReport(this);
}
public int getIncome() {
return income;
}
public void setExpenditure(int expenditure) {
this.expenditure = expenditure;
}
public int getExpenditure() {
return expenditure;
}
} |
销售报表类:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
public class LogisticsReport extends Reporter {
private int production = 800;
private int sale=40;
@Override
public void accept(Leader leader) {
leader.visitLogisticsReport(this);
}
public int getProduction() {
return production;
}
public int getSale() {
return sale;
}
} |
报表管理者,相当于结构对象:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
public class ReportManage {
private List<Reporter> reporters = new ArrayList<Reporter>();
public void attach(Reporter reporter){
reporters.add(reporter);
}
public void detach(Reporter reporter){
reporters.remove(reporter);
}
public void accept(Leader leader){
for (int i = 0; i < reporters.size(); i++) {
(reporters.get(i)).accept(leader);
}
}
} |
客户端:
|
1
2
3
4
5
6
7
8
9
|
public static void main(String[] args) {
ReportManage reportManage = new ReportManage();
reportManage.attach(new FinancialReport());
reportManage.attach(new LogisticsReport());
FinanceDirector financeDirector = new FinanceDirector();
SalesDirector salesDirector = new SalesDirector();
reportManage.accept(financeDirector);
reportManage.accept(salesDirector);;
}
|
可以看出。报表类的accept方法限定了可以访问报表对象的只有领导类,算是一种访问控制的形式。而每个领导只关心自己的报表进行访问并计算,就是说如果加入新的算法,只需要添加新的领导类并实现算法即可,那么要增加新的报表结构,那么领导抽象类及具体的子类也要相应的修改,这就是为什么访问者模式适用于数据结构比较稳定的系统的原因。
访问者模式适用于以下几种情况:
1、当一个对象结构包含有很多类对象,但是他们哟不同的接口,并且开发人员希望对这些对象实施一些依赖于其他具体类的操作时。
2、当需要一个对象结构中的进行很多不同的并且不相关的操作时。
3、当该对象结构被很多应用共享时。