软件设计模式学习(二十七)访问者模式


访问者模式是一种较为复杂的行为型设计模式,它包含访问者和被访问元素两个主要组成部分,这些被访问的元素具备不一样的类型,且不一样的访问者能够对其进行不一样的访问操做java


模式动机

对于系统中某些对象,它们存储在同一个集合中,且具备不一样的类型。对于该集合中的对象,能够接受一类称为访问者的对象来访问,不一样的访问者其访问方式有所不一样。设计模式

在 Java 等面向对象语言中都提供了大量用于存储多个元素的集合对象,集合中存储的对象有时候是同一类型,有时候不是同一类型,或许它们只是具备共同的父类。假如咱们要针对一个包含不一样类型元素的集合采起某种操做,而操做细节根据元素类型不一样而不一样,就会出现大量类型判断语句,增大代码复杂度。this

实际使用时,对相同元素的对象也可能存在多种不一样的操做方式,并且可能还须要增长新的操做,此时访问者模式是一个值得考虑的解决方案。设计


模式定义

表示一个做用于某对象结构中的各元素的操做,它使咱们能够在不改变各元素的类的前提下定义做用于这些元素的新操做。访问者模式是一种对象行为型模式。code

Represent an operation to be performedd on the elements of an object structure. Visitor lets you define a new operation without changing the classes of the elements on which it operates.orm


模式分析

访问者模式结构较为复杂,首先看一张模式结构类图对象

对象结构(ObjectStructure)是一个元素集合,存储了不一样类型的元素对象,以供不一样访问者访问。访问者模式包括两个层次,一个是访问者层次结构,另外一个是元素层次结构。blog

访问者层次结构提供了抽象访问者(Visitor)和具体访问者(ConcreteVisitor)。抽象访问者声明了访问元素对象的方法,一般为每一种类型的元素对象都提供一个访问方法,而具体访问者能够实现这些访问方法。element

这些访问方法的设计又有两种,一种是直接在方法名中标明待访问元素对象的类型,如 visitConcreteElementA(ConcreteElementA elementA),还有一种是统一取名为 visit(),经过参数类型的不一样来定义一系列重载方法。rem

public abstract class Visitor {
    // 统一取名
    public abstract void visit(ConcreteElementA elementA);
    public abstract void visit(ConcreteElementB elementB);
    // 若是全部访问者对某一类型的元素访问操做都相同
    // 则能够将操做代码移到抽象访问者中
    public void visit(ConcreteElementC elementC) {
        ...
    }
}

元素层次结构提供了抽象元素类(Element)和具体元素类(ConcreteElementA),抽象元素类通常都声明一个 accept() 方法,用于接受访问者的访问。该方法传入一个抽象访问者 Visitor 类型的参数,在程序运行时肯定其具体访问者的类型,并调用具体访问者对象的 visit() 方法实现对元素对象的操做

public class ConcreteElementA implements Element {
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }
    public void operationA() {
        // 在具体元素类中能够定义不一样类型的元素所特有的业务方法
    }
}

具体元素类 ConcreteElementA 的 accept() 方法经过调用 Visitor 类的 visit() 方法实现对元素的访问,并以当前对象做为 visit() 方法的参数,这种调用机制也称“双重分派”。正由于使用了双重分派技术,使得增长新的访问者无须修改现有类库代码,只需将新的访问者对象传入具体元素对象的 accept() 方法便可,程序运行时将回调在 Visitor 类中定义的 visit() 方法,从而实现不一样形式的访问。

对象结构(ObjectStructure)是一个集合,用于存储元素对象并接受访问者的访问。在对象结构中可使用迭代器对存储在集合中的元素对象进行遍历,并逐个调用每个对象的 accept() 方法,实现对元素对象的访问操做。

public class ObjectStructure {
    
    private ArrayList list = new ArrayList();
    
    public void accept(Visitor visitor) {
        Iterator i = list.iterator();
        while(i.hashNext()) {
            ((Element)i.next()).accept(visitor);
        }
    }
    
    public void addElement(Element element) {
		list.add(element);
    }
    
    public void removeElement(Element element) {
        list.remove(element);
    }
}

最终在客户端咱们须要实例化一个对象结构对象,并向其添加元素对象,再调用 accept() 方法来接受访问者对象的访问。具体访问者类型能够经过配置文件来肯定。

public class Client {
    
    public static void main(String[] args) {
        Element elementA = new ElementA();
        Element elementB = new ElementB();
        Element elementC = new ElementC();
        
        ObjectStructure objectStructure = new ObjectStructure();
        objectStructure.addElement(elementA);
        objectStructure.addElement(elementB);
        objectStructure.addElement(elementC);
        
        Visitor visitor = new ConcreteVisitorA();
        objectStructure.accept(visitor);
    }
}

若是须要修改访问者类型,只或者增长新的类型的访问者,只需修改配置文件便可,符合开闭原则。但若是要增长新的类型的具体元素类,则访问者类须要为其定义新的访问方法,从这一点看又违背了开闭原则。


模式优缺点

访问者模式的优势:

  • 使得增长新的访问操做变得容易,无须修改现有类库的代码
  • 将有关类对象的访问行为i集中到一个访问者对象中,而不是分散到一个个元素类,类的职责更加清晰
  • 能够跨过类的等级结构访问不一样等级结构的元素类
  • 用户可以在不修改现有类层次结构的状况下,定义该类层次结构的新操做

访问者模式的缺点:

  • 增长新的元素类很困难
  • 访问者模式要求访问者对象访问并调用每个元素对象的操做,破坏了封装性
相关文章
相关标签/搜索