访问者模式介绍
访问者模式是一种将数据操作与数据结果分离的设计模式,在23中设计模式中最复杂的一个,使用频率不高。
访问这模式的基本想法是,软件系统中拥有一个由许多对象构成的、比较稳定的对象结构,这写对象的类都拥有一个accept方法用来接受访问者对象的访问。访问者是一个接口,它拥有一个visit方法,这个方法对访问到的对象结构中不同类型的元素做出不同的处理。在对象结构的一次访问过程中。我们遍历整个对象结构,对每一个元素都实施accept方法,在每一个元素的accept方法中会调用访问者的visit方法,从而使访问者得以处理对象结构的每一个元素,我们可针对对像结构设计不同的访问者类来完成不同的操纵,达到区别对待效果。
访问者模式的定义
封装一些作用于某种数据结构中的的各元素的操作,它可以在不改变这个数据结构的前提下定义作用于这些元素的新的操作。
访问者模式的使用场景
- 对象结构比较稳定,但经常需要在此对象结构上定义新的操作
- 需要对一个对象结构中的对象进行很多不同的并且不相关的操作,而需要避免这些操作‘污染’这些对象的类,也不希望在增加新操作时修改这些类。
访问者模式的UML类图
这里写图片描述
代码示例:
接口
public interface Visitor {
public void visit(GladiolusConcreteElement gladiolus);
public void visit(ChrysanthemumConreteElement chrysanthemum);
}
接口
public interface FlowerElement {
public void accept(Visitor visitor);
}
public class GladiolusVisitor implements Visitor {
@Override
public void visit(GladiolusConcreteElement gladiolus) {
System.out.println(this.getClass().getSimpleName() + " access " + gladiolus.getClass().getSimpleName());
}
@Override
public void visit(ChrysanthemumConreteElement chrysanthemum) {
System.out.println(this.getClass().getSimpleName() + " access " + chrysanthemum.getClass().getSimpleName());
}
}
public class GladiolusVisitor implements Visitor {
@Override
public void visit(GladiolusConcreteElement gladiolus) {
System.out.println(this.getClass().getSimpleName() + " access " + gladiolus.getClass().getSimpleName());
}
@Override
public void visit(ChrysanthemumConreteElement chrysanthemum) {
System.out.println(this.getClass().getSimpleName() + " access " + chrysanthemum.getClass().getSimpleName());
}
}
public class ChrysanthemumConreteElement implements FlowerElement {
public void accept(Visitor visitor) {
visitor.visit(this);//调用visitor里面的visit方法,传的是本对象的参数
}
}
public class GladiolusConcreteElement implements FlowerElement {
public void accept(Visitor visitor) {
visitor.visit(this);//调用visitor里面的visit方法,传的是本对象的参数
}
}
public class ObjectStructure {
private final List<FlowerElement> elements = new ArrayList<>();
//添加元素到集合
public void addElement(final FlowerElement element){
elements.add(element);
}
//在集合中删除指定元素
public void removeElement(final FlowerElement e){
elements.remove(e);
}
public void accept(final Visitor visitor){
for(final FlowerElement e:elements){
//调用的是FlowerElement实现类里面的accept方法,这个方法里面又是调用的是visitor对象里面的visit方法,传的是FlowerElement实现类的对象为参数,最后在visitor里面的visit方法处理逻辑,业务输出等
e.accept(visitor);
}
}
}
public class Client {
public static void main(String[] args) {
final ObjectStructure os = new ObjectStructure();
//往集合中添加元素
os.addElement(new GladiolusConcreteElement());
os.addElement(new ChrysanthemumConreteElement());
//声明Visitor接口的实现类
final GladiolusVisitor gVisitor = new GladiolusVisitor();
final ChrysanthemumVisitor chVisitor = new ChrysanthemumVisitor();
//调用了ObjectStructure结构管理类里面的accept方法,方法里面调用的是集合中FlowerElement接口实现类的accept方法
os.accept(gVisitor);
os.accept(chVisitor);
}
}
运行结构:
GladiolusVisitor access GladiolusConcreteElement
GladiolusVisitor access ChrysanthemumConreteElement
ChrysanthemumVisitor access GladiolusConcreteElement
ChrysanthemumVisitor access ChrysanthemumConreteElement
总结
优点
1. 各角色职责分离,符号单一职责原则
2. 具有优秀的扩展性
3. 使得数据结构和作用于结构上的操作解耦,使得操作集合可以独立变化
4. 灵活性
缺点
1. 具体元素对访问这公布细节,违反了迪米特原则
2. 具体元素变更时导致修改成本大
3. 违反了依赖倒置原则,为了达到‘区别对待’而依赖了具体类,没有依赖抽象