从零开始学设计模式(十三):访问者模式(Visitor Pattern)

简介: 前面的几篇文章分别介绍了创建型设计模式和结构型设计模式,接下来的几篇文章将介绍行为型设计模式

什么是行为型设计模式


前面的几篇文章分别介绍了创建型设计模式和结构型设计模式,接下来的几篇文章将介绍行为型设计模式。


创建型模式(Creational Pattern)指的是对类的实例化过程进行了抽象,使得能够将软件模块中对象的创建和对象的使用分离。外界对于这些对象只需要知道它们共同的接口,而不用清楚其具体的实现细节,使得系统设计更符合单一职责原则,软件的结构也更加清晰。


结构型模式(Structural Pattern)则指的是如何将类或者对象结合在一起从而形成更大的结构,通过各种组合形式从而形成复杂的、功能更为强大的结构体系。


行为型模式(Behavioral Pattern)指的是对在不同的对象之间划分责任和算法的抽象化。


它不仅仅关注类和对象的结构,而且还重点关注它们之间的相互作用。通过行为型模式,可以更加清晰地划分类与对象的职责。


行为型模式分为类行为型模式对象行为型模式两种:


类行为型模式:类的行为型模式使用继承关系在几个类之间分配行为,类行为型模式主要通过多态等方式来分配父类与子类的职责。


对象行为型模式:对象的行为型模式则使用对象的聚合关联关系来分配行为,对象行为型模式主要是通过对象关联等方式来分配两个或多个类的职责。根据“合成复用原则”,系统中要尽量


使用关联关系来取代继承关系,大部分行为型设计模式都属于对象行为型设计模式。


介绍的第一个行为型设计模式是----访问者模式!


定义


访问者模式指的是将某些作用于某种数据结构中各元素的操作分离出来封装成独立的类,它可以在不改变数据结构的前提下定义作用于这些元素的新的操作。它是一种类行为型设计模式!它也是行为类模式中最复杂的一种模式,也是使用较多的一种行为型设计模式!


组成部分


访问者模式主要包含以下几个部分:


1、抽象访问者(Visitor)这里主要用来定义一个访问具体元素的接口,并且为每个具体元素类对应一个访问操作方法,并且在该操作中的参数类型标识了被访问的具体元素。


2、具体访问者(ConcreteVisitor):它主要实现抽象访问者角色中声明的各个访问操作,确定访问者访问一个元素时该做什么。


3、抽象元素(Element):这里声明一个包含接受操作的接口,被接受的访问者对象作为 接受法的参数。


4、具体元素(ConcreteElement):实现抽象元素角色提供的接受操作,另外具体元素中可能还包含本身业务逻辑的相关操作。


5、对象结构(Object Structure):一个元素的容器,一般包含一个容纳多个不同类、不同接口的容器,提供让访问者对象遍历容器中的所有元素的方法,通常由 List、Set、Map这类的聚合类实现,但是在项目中一般很少抽象出这个角色。


栗子


首先来看一个简单的例子,先声明一个抽象访问者Visitor:


public interface Visitor {
    public void visit(ConcreteElement1 el1);
    public void visit(ConcreteElement2 el2);
}
复制代码


接着声明一个抽象元素Element两个具体元素ConcreteElement并且继承抽象元素Element:


public abstract class Element {
    public abstract void accept(Visitor visitor);
    public abstract void print();
}
public class ConcreteElement1 extends Element{
    @Override
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }
    @Override
    public void print(){
        System.out.println("这是具体元素ConcreteElement1");
    }
}
public class ConcreteElement2 extends  Element {
    @Override
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }
    @Override
    public void print() {
        System.out.println("这是具体元素ConcreteElement2");
    }
}
复制代码


然后定义一个具体访问者ConcreteVisitor实现Visitor接口:


public class ConcreteVisitor implements Visitor {
    @Override
    public void visit(ConcreteElement1 el1) {
        el1.print();
    }
    @Override
    public void visit(ConcreteElement2 el2) {
        el2.print();
    }
}
复制代码


最后一部分就是对象结构Object Structure,代码如下:


public class ObjectStruture {
    public static List<Element> getList(){
        List<Element> list = new ArrayList<Element>();
        Random ran = new Random();
        for(int i=0; i<10; i++){
            int a = ran.nextInt(100);
            if(a>50){
                list.add(new ConcreteElement1());
            }else{
                list.add(new ConcreteElement2());
            }
        }
        return list;
    }
}
复制代码


最后的最后就是测试代码了:


public class VisitorPatternTest {
    public static void main(String[] args) {
        List<Element> list = ObjectStruture.getList();
        for(Element e: list){
            e.accept(new ConcreteVisitor());
        }
    }
}
复制代码


运行结果如下:


252bf4af5b9d4029857375451d793db2~tplv-k3u1fbpfcp-zoom-in-crop-mark_1304_0_0_0.webp.jpg


通过上面的例子,可以对访问者模式的特点(优缺点)进行总结了。


访问者模式的优点


1、前面提到了访问者模式是符合单一职责原则的。在访问者设计模式的代码中元素类中需要封装在访问者中的操作必定是与元素类本身关系不大且是易变的操作,使用访问者模式一方面符合单一职责原则。


2、通过上面代码可以发现访问者模式的扩展性良好,因为被封装的操作通常来说都是易变的,元素类可以通过接受不同的访问者来实现对不同操作的扩展。所以当发生变化时,就可以在不改变元素类本身的前提下,实现对变化部分的扩展。


3、访问者模式代码复用性好。因为可以通过访问者来定义整个对象结构通用的功能,从而提高系统的复用程度。


4、访问者模式灵活性好。因为访问者模式将数据结构与作用于结构上的操作解耦,使得操作集合可相对自由地演化而不影响系统的数据结构。


访问者模式的缺点


访问者模式的缺点也很明显:


1、访问者模式的代码中增加新的元素类困难。因为一旦增加一个新的元素类,都需要在每一个具体访问者类中去增加相应的具体操作,这很显然违背了“开闭原则”。


2、违反了依赖倒置原则。因为访问者模式依赖了具体类,而没有依赖抽象类。


适用场景


1、如果一个对象中存在着一些与本对象不相干的操作,为了避免这些操作影响这个对象,则可以使用访问者模式来把这些操作封装到访问者中去。


2、或者在一组对象中,存在着相似的操作,为了避免出现大量重复的代码,也可以将这些重复的操作封装到访问者中去。


3、对象结构包含很多类型的对象,希望对这些对象实施一些依赖于其具体类型的操作


4、对象结构相对稳定,但其操作算法经常变化的系统


总结


以上就是关于行为型设计模式中的访问者设计模式的介绍。


访问者模式指的是将某些作用于某种数据结构中各元素的操作分离出来封装成独立的类,它可以在不改变数据结构的前提下定义作用于这些元素的新的操作。

目录
相关文章
|
1月前
|
设计模式 JavaScript 前端开发
JavaScript设计模式--访问者模式
【10月更文挑战第1天】
30 3
|
2月前
|
设计模式
设计模式-工厂模式 Factory Pattern(简单工厂、工厂方法、抽象工厂)
这篇文章详细解释了工厂模式,包括简单工厂、工厂方法和抽象工厂三种类型。每种模式都通过代码示例展示了其应用场景和实现方法,并比较了它们之间的差异。简单工厂模式通过一个工厂类来创建各种产品;工厂方法模式通过定义一个创建对象的接口,由子类决定实例化哪个类;抽象工厂模式提供一个创建相关或依赖对象家族的接口,而不需要明确指定具体类。
设计模式-工厂模式 Factory Pattern(简单工厂、工厂方法、抽象工厂)
|
6月前
|
设计模式 算法 Java
【设计模式】JAVA Design Patterns——Acyclic Visitor(非循环访问者模式)
【设计模式】JAVA Design Patterns——Acyclic Visitor(非循环访问者模式)
|
2月前
|
设计模式 Java
设计模式--适配器模式 Adapter Pattern
这篇文章介绍了适配器模式,包括其基本介绍、工作原理以及类适配器模式、对象适配器模式和接口适配器模式三种实现方式。
|
2月前
|
设计模式 缓存 算法
Java设计模式-访问者模式(22)
Java设计模式-访问者模式(22)
|
5月前
|
设计模式
设计模式-05建造者模式(Builder Pattern)
设计模式-05建造者模式(Builder Pattern)
|
6月前
|
设计模式 安全 Java
【设计模式】JAVA Design Patterns——Curiously Recurring Template Pattern(奇异递归模板模式)
该文介绍了一种C++的编程技巧——奇异递归模板模式(CRTP),旨在让派生组件能继承基本组件的特定功能。通过示例展示了如何创建一个`Fighter`接口和`MmaFighter`类,其中`MmaFighter`及其子类如`MmaBantamweightFighter`和`MmaHeavyweightFighter`强制类型安全,确保相同重量级的拳手之间才能进行比赛。这种设计避免了不同重量级拳手间的错误匹配,编译时会报错。CRTP适用于处理类型冲突、参数化类方法和限制方法只对相同类型实例生效的情况。
【设计模式】JAVA Design Patterns——Curiously Recurring Template Pattern(奇异递归模板模式)
|
6月前
|
设计模式 安全 Java
【设计模式】字节三面:请举例阐释访问者模式
【设计模式】字节三面:请举例阐释访问者模式
43 2
|
6月前
|
设计模式 存储 Java
Java设计模式:解释一下单例模式(Singleton Pattern)。
`Singleton Pattern`是Java中的创建型设计模式,确保类只有一个实例并提供全局访问点。它通过私有化构造函数,用静态方法返回唯一的实例。类内静态变量存储此实例,对外仅通过静态方法访问。
49 1
|
6月前
|
设计模式 Go
[设计模式 Go实现] 行为型~访问者模式
[设计模式 Go实现] 行为型~访问者模式