begin 2023年04月02日15:56:19
引子
定义
表示在对象结构的元素上执行的操作。访问者模式(Visitor)允许您定义一种新操作,而无需更改它所作用的元素的类。——《设计模式:可复用面向对象软件的基础》
访问者模式是一种行为型设计模式。
使用场景
- 对象机构包含了许多具有不同接口的对象类,您希望对这些对象执行依赖于其具体类的操作。
- 需要对对象结构中的对象执行许多不同且不相关的操作,并且您希望避免这些操作“污染”它们的类。Visitor允许将相关操作定义在一个类中,从而将它们放在一起。当对象结构被许多应用程序共享时,使用Visitor将操作放在需要它们的应用程序中。
- 定义对象结构的类很少改变,但是您经常希望在类上定义新的操作。更改对象结构类需要为所有访问者重新定义接口,这可能成本很高。如果对象结构类经常变化,那么最好在这些类中定义操作。
图示
访问者模式结构图:
角色
抽象访问者角色(Visitor):
- 为对象结构中的每个 ConcreteElement 类声明一个 visit 操作。
- 操作的名称和签名(visitConcreteElementA、visitConcreteElementB)标识向访问者(ConcreteVisitorA、ConcreteVisitor)发送 visit 请求的类,让访问者可以确定所访问元素的具体类(ConcreteElementA、ConcreteElementB)。
- 然后访问者可以通过元素特定的接口直接访问该元素。
具体访问者角色(ConcreteVisitorA、ConcreteVisitorB):
- 实现访问者声明的每个操作。
- 每个操作实现为对象结构中对应的对象类定义的算法片段(针对具体元素所执行的操作,如获取ConcreteElementA的名字等)
- ConcreteVisitor 为算法提供了上下文,并存储其本地状态。该状态通常在遍历对象结构时积累结果。
对象结构角色(ObjectStructure):
- 可以枚举其元素。
- 可以提供一个高层接口,以允许访问者访问其元素。
- 可以是一个组合(参见组合模式)或者一个集合,如列表或集合
抽象元素角色(Element):
- 定义一个接受访问者作为参数的 Accept 操作。
具体元素角色(ConcreteElementA、ConcreteElementB):
- 实现一个接受访问者作为参数的 Accept 操作。
代码示例
生命主要分为过去、现在、未来,乐观者看到不念过去,不畏将来,立足现在努力,悲观者看到悔恨过去,迷茫未来,或不知所措的现在,同样的生命不同的人看到不同的世界。
代码示例类图:
代码示例:
抽象访问者角色:
// 人类
public interface Man {
void visitPast(Past past);
void visitPresent(Present present);
void visitFuture(Future future);
}
具体访问者角色:
// 乐观主义者
public class Optimist implements Man {
@Override
public void visitPast(Past past) {
System.out.println("不念" + past.getName());
}
@Override
public void visitPresent(Present present) {
System.out.println("享受" + present.getName());
}
@Override
public void visitFuture(Future future) {
System.out.println("不畏" + future.getName());
}
}
// 悲观主义者
public class Pessimist implements Man {
@Override
public void visitPast(Past past) {
System.out.println("悔恨" + past.getName());
}
@Override
public void visitPresent(Present present) {
System.out.println("焦虑" + present.getName());
}
@Override
public void visitFuture(Future future) {
System.out.println("迷茫" + future.getName());
}
}
对象结构角色:
// 生命
public class Life {
private List<Time> timeList = new ArrayList<>();
public Life() {
timeList.add(new Past());
timeList.add(new Present());
timeList.add(new Future());
}
public void visitTime(Man man) {
for (Time time : timeList) {
if (time instanceof Past) {
man.visitPast((Past) time);
} else if (time instanceof Present) {
man.visitPresent((Present) time);
} else if (time instanceof Future) {
man.visitFuture((Future) time);
}
}
}
}
抽象元素角色:
// 时间
public interface Time {
void accept(Man man);
String getName();
}
具体元素角色:
// 过去
public class Past implements Time {
private String name = "过去";
@Override
public void accept(Man man) {
man.visitPast(this);
}
public String getName() {
return name;
}
}
// 现在
public class Present implements Time {
private String name = "现在";
@Override
public void accept(Man man) {
man.visitPresent(this);
}
public String getName() {
return name;
}
}
// 未来
public class Future implements Time {
private String name = "未来";
@Override
public void accept(Man man) {
man.visitFuture(this);
}
public String getName() {
return name;
}
}
客户端:
public class Client {
public static void main(String[] args) {
Optimist optimist = new Optimist();
Pessimist pessimist = new Pessimist();
Life life = new Life();
System.out.println("乐观者:");
life.visitTime(optimist);
System.out.println("悲观者:");
life.visitTime(pessimist);
}
}
结果:
乐观者:
不念过去
享受现在
不畏未来
悲观者:
悔恨过去
焦虑现在
迷茫未来
优点
- 操作和结构分开,易于新增操作
缺点
- 修改结构需要修改所有操作类,成本极大
总结
访问者莫斯允许您定义一种新操作,而无需更改它所作用的元素的类。访问者模式适用于结构固定,但是操作不固定的对象,它把对象结构和作用于结构的操作耦合解开,方便增加新的操作。
end 2023年04月05日15:22:07