设计模式-访问者模式

设计模式-访问者模式

访问者者模式的英文翻译是 Visitor Design Pattern。它是这么定义的:Allows for one or more operation to be applied to a set of objects at runtime, decoupling the operations from the object structure. 翻译成中文就是:允许一个或者多个操作应用到一组对象上,解耦操作和对象本身。

案例分析

如果有一个接口,这个接口有三个实现类,那么我们可以充分利用多态特性进行处理

java 复制代码
public interface Visit {

    void visit();

}

public class AVisitor implements Visit {

    @Override
    public void visit() {
        System.out.println("AVisitor:visit");
    }

}

public class BVisitor implements Visit {

    @Override
    public void visit() {
        System.out.println("BVisitor:visit");
    }
    
}

public class CVisitor implements Visit {
    @Override
    public void visit() {
        System.out.println("CVisitor:visit");
    }

}

由于这三个实现类都实现了该接口,因此可以借助多态特性使用

java 复制代码
public class Main {

    public static void main(String[] args) {
        List<String> types = List.of("A","B","C");
        String type = types.get(new Random().nextInt(3));
        Visit visit = new AVisitor();
        if (type.equals("A")) {
            visit = new AVisitor();
        }
        if (type.equals("B")) {
            visit = new BVisitor();
        }
        if (type.equals("C")) {
            visit = new CVisitor();
        }
        processVisit(visit);
    }

    private static void processVisit(Visit visit) {
        visit.visit();
    }

}

这也是我们经常用到的方式

但是随着接口的方法增加,所有的实现类都需要新增实现接口的内容,如果接口的内容过多,会导致实现类的内容非常庞大,那么我们可以反向思考,按照功能实现接口,还是如上的场景,例如 ABC 三个实现类都需要实现接口中的 funcation1 和 funcation2 方法,我们定义如下接口

java 复制代码
public interface Visit {

    void visit(AFuncationImpl a);

    void visit(BFuncationImpl b);

    void visit(CFuncationImpl c);

}

利用接口重载支持多个实现类,接着我们按照功能拆分为 funcation1 类 和 funcation2 类

java 复制代码
public class Funcation1Visitor implements Visit {

    @Override
    public void visit(AFuncationImpl a) {
        System.out.println("AVisitor Funcation1");
    }

    @Override
    public void visit(BFuncationImpl b) {
        System.out.println("BVisitor Funcation1");
    }

    @Override
    public void visit(CFuncationImpl c) {
        System.out.println("CVisitor Funcation1");
    }

}

public class Funcation2Visitor implements Visit {

    @Override
    public void visit(AFuncationImpl a) {
        System.out.println("AVisitor Funcation2");
    }

    @Override
    public void visit(BFuncationImpl b) {
        System.out.println("BVisitor Funcation2");
    }

    @Override
    public void visit(CFuncationImpl c) {
        System.out.println("CVisitor Funcation2");
    }

}

经过这样的拆分,可以看出每个 Funcation 中一般只有实现类个方法。

那么该如何使用呢,每一个 FuncationVisitor 的参数已经变成具体的实现类类,是不是就无法充分利用多态特性了?

我们可以再定义一个接口

java 复制代码
public interface Accept {

    void accept(Visit visit);

}

所有的 CFuncationImpl 实现这个接口,并传入具体的 FuncationVisitor,这样就能充分利用多态特性了

java 复制代码
public class AFuncationImpl implements Accept {

    @Override
    public void accept(Visit visit) {
        visit.visit(this);
    }

}

public class BFuncationImpl implements Accept {

    @Override
    public void accept(Visit visit) {
        visit.visit(this);
    }

}

public class CFuncationImpl implements Accept {

    @Override
    public void accept(Visit visit) {
        visit.visit(this);
    }

}

测试代码:

java 复制代码
public class Main {

    public static void main(String[] args) {
        List<Accept> acceptList = List.of(new AFuncationImpl(), new BFuncationImpl(), new CFuncationImpl());

        Visit visit = new Funcation1Visitor();
        for (Accept accept : acceptList) {
            accept.accept(visit);
        }

        visit = new Funcation2Visitor();
        for (Accept accept : acceptList) {
            accept.accept(visit);
        }
    }

}

类之间关系如图:

梳理一下改动的思路,由于接口中的方法越来越多会导致实现类的代码越来越多,访问者模式提供了一种思路按照功能进行抽象(Visit),利用接口重载为所有的实现类设置一个方法(Visit.visit),并让所有的功能类实现这个方法。

由于功能类实现后正常情况下无法利用多态特性(此时的参数是具体实现类),因此可以让具体实现类(AFuncationImpl、BFuncationImpl等)实现一个统一的接口(Accept)。

访问者模式为了避免不断添加功能导致类不断膨胀,职责越来越不单一,以及避免频繁地添加功能导致的频繁代码修改,将对象与操作解耦,将这些业务操作抽离出来,定义在独立细分的访问者类中。

相关推荐
bkspiderx4 小时前
C++设计模式之行为型模式:模板方法模式(Template Method)
c++·设计模式·模板方法模式
o0向阳而生0o4 小时前
108、23种设计模式之模板方法模式(17/23)
设计模式·模板方法模式
canonical_entropy7 小时前
组合为什么优于继承:从工程实践到数学本质
后端·数学·设计模式
Deschen19 小时前
设计模式-工厂模式
设计模式·简单工厂模式
阿无,19 小时前
Java设计模式之工厂模式
java·开发语言·设计模式
Camel卡蒙21 小时前
DDD架构——充血模型、领域模型
java·设计模式·架构
rongqing201921 小时前
Google 智能体设计模式:目标设定与监控
设计模式
weixin_445476681 天前
一天一个设计模式——开闭原则
服务器·设计模式·开闭原则
李广坤1 天前
模板方法模式(Template Method Pattern)
设计模式