23种设计模式之访问者模式
行为型设计模式
访问者模式是一种将算法与对象结构分离的软件设计模式。
提供一个作用于某对象结构中的各元素的操作表示,它使得可以在不改变各元素的类的前提下定义作用于这些元素的新操作。访问者模式是一种对象行为型模式。
介绍
意图: 首先我们拥有一个由许多对象(子对象)构成的对象结构,这些对象(子对象)的类都拥有一个 accept 方法来接受访问者对象,访问者是一个接口,它拥有一个 visit 方法,这个方法对访问到的对象结构中不同类型的元素(子对象)作出不同的反应;在对象结构的一次访问过程中,我们遍历整个对象结构,对每一个元素都实施accept方法,在每一个元素的accept方法中回调访问者的visit方法,从而使访问者得以处理对象结构的每一个元素。我们可以针对对象结构设计不同的实在的访问者类来完成不同的操作。
优点:
- 增加新的访问操作十分方便,符合开闭原则;
- 将有关元素对象的访问行为集中到一个访问者对象中,而不是分散在一个个的元素类中,类的职责更加清晰,符合单一职责原则
缺点:
- 增加新的元素类很困难,需要在每一个访问者类中增加相应访问操作代码,这违背了开闭原则;(访问者模式与抽象工厂模式类似,对于开闭原则的支持具有“倾斜”性,可以方便地新增访问者,但是添加新的元素较为麻烦。)
- 元素对象有时候必须暴露一些自己的内部操作和状态,否则无法供访问者访问,这破坏了元素的封装性。
主要角色:
- 访问者接口(Visitor)
- 被访问者接口(Visitable)
- 具体访问者
- 具体被访问者类
- 对象结构:一个元素的集合,存放元素对象。
核心代码:
对象结构类对象,结构类对象中有很多子对象组成,子对象都继承同一个接口,接口包含一个子对象都需要重写的方法。访问者接口,访问者接口的实现类中重写各种不同类型的访问者访问子对象实现的逻辑。
应用场景:
- 一个对象结构包含多个类型的对象,不同的类型可以有不同的访问操作
- 对象结构中对象对应的类很少改变,但经常需要在此对象结构上定义新的操作。
代码实现
/**
* 汽车中的元素很稳定,这些几乎不可能改变,而最容易改变的就是访问者这部分。
* 访问者模式最大的优点就是增加访问者非常容易
*/
// Visitable:被访问者类
public interface Visitable {
void accept(Visitor visitor);
}
public class Car implements Visitable {
private Engine engine;
private Body body;
// 可访问元素的对象集合
private List<Visitable> visitList = new ArrayList<>();
public void addVisit(Visitable visitable) {
visit.add(visitable);
}
@Override
public void accept(Visitor visitor) {
for (Visitable visitable: visitList) {
visitable.accept(visitor);
}
}
}
public class Engine implements Visitable {
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
}
public class Body implements Visitable {
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
}
// 访问者类
public interface Visitor {
void visit(Engine engine);
void visit(Body body);
}
public class PrintCar implements Visitor {
@Override
public void visit(Engine engine) {
System.out.println("Visiting engine");
}
@Override
public void visit(Body body) {
System.out.println("Visiting body");
}
}
public class CheckCar implements Visitor {
@Override
public void visit(Engine engine) {
System.out.println("Check engine");
}
@Override
public void visit(Body body) {
System.out.println("Check body");
}
}
public class Client {
static public void main(String[] args) {
Car car = new Car();
car.addVisit(new Body());
car.addVisit(new Engine());
Visitor print = new PrintCar();
car.accept(print);
}
}