软件设计模式修炼 -- 访问者模式

访问者模式是一种较为复杂的行为型设计模式,它包含访问者和被访问元素两个主要组成部分,这些被访问的元素具有不同的类型,且不同的访问者可以对其进行不同的访问操作

模式动机

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

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

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

模式定义

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

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.

模式分析

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

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

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

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

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集中到一个访问者对象中,而不是分散到一个个元素类,类的职责更加清晰
  • 可以跨过类的等级结构访问不同等级结构的元素类
  • 用户能够在不修改现有类层次结构的情况下,定义该类层次结构的新操作

访问者模式的缺点:

  • 增加新的元素类很困难
  • 访问者模式要求访问者对象访问并调用每一个元素对象的操作,破坏了封装性
(0)

相关推荐

  • 诚之和:设计模式之什么是访问者模式

    本篇内容介绍了"设计模式之什么是访问者模式"的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学 ...

  • PHP设计模式—访问者模式

    定义: 访问者模式(Visitor):表示一个作用于某对象结构中的各元素的操作.它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作. 结构: Visitor:抽象访问者,为该对象结构中Co ...

  • 访问者模式

    假设有男人和女人两种元素,要分别打印出他们在不同状态时的不同表现. 用OO的思想把表现(行为)提取出来作为一个抽象方法,代码如下: 用if-else对状态进行判断  Person接口 public i ...

  • 设计模式(十六)——访问者模式

    设计模式(十六)——访问者模式

  • C#设计模式学习笔记:(21)访问者模式

    本笔记摘抄自:https://www.cnblogs.com/PatrickLiu/p/8135083.html,记录一下学习过程以备后续查用. 一.引言 今天我们要讲行为型设计模式的第九个模式--访 ...

  • 软件设计模式修炼 -- 迭代器模式

    迭代器模式是一种使用频率非常高的设计模式,迭代器用于对一个聚合对象进行遍历.通过引入迭代器可以将数据的遍历功能从聚合对象中分离出来,聚合对象只负责存储数据,聚合对象只负责存储数据,而遍历数据由迭代器来 ...

  • 软件设计模式修炼 -- 解释器模式

    解释器是一种不常使用的设计模式,它用于描述如何构成一个简单的语言解释器,主要应用于使用面向对象语言开发的编译器和解释器设计.当我们需要开发一个新的语言时,可以考虑使用解释器模式 模式动机 如果在系统中 ...

  • PHP设计模式之访问者模式

    PHP设计模式之访问者模式 访问者,就像我们去别人家访问,或者别人来我们家看望我们一样.我们每个人都像是一个实体,而来访的人都会一一的和我们打招呼.毕竟,我们中华民族是非常讲究礼数和好客的民族.访问者 ...

  • [PHP小课堂]PHP设计模式之访问者模式

    [PHP小课堂]PHP设计模式之访问者模式 关注公众号:[硬核项目经理]获取最新文章 添加微信/QQ好友:[DarkMatterZyCoder/149844827]免费得PHP.项目管理学习资料

  • 软件设计模式修炼 -- 观察者模式

    观察者模式是一种经常使用的设计模式,在软件系统中对象并不是孤立存在的,一个对象行为的改变可能会导致其他与之存在依赖关系的对象行为发生改变,观察者模式用于描述对象之间的依赖关系. 模式动机 很多情况下, ...

  • 软件设计模式-中介者模式

    使用中介者模式来说明联合国的作用,要求绘制相应的类图并分析每个类的作用(注:可以将联合国定义为抽象中介者类,联合国下属机构如WIO,WHO,WTO等作为具体者类,国家作为抽象同事类,而将中国,美国等国 ...