【设计模式】访问者模式

  |   0 评论   |   107 浏览

简介

封装作用于某数据结构中的各元素的操作,可以在不改变各元素类的前提下,定义作用于这些元素的操作,将算法与数据结构进行分离,本质上,访问者允许在不修改类的情况下向类添加新的虚拟函数。属于行为型。

适用场景

1、一个数据结构(List/Map等)包含很多类型对象
2、数据结构与数据操作分离
3、需要对对象结构进行许多不相关的操作
4、组成对象结构的类是已知的,并且不会改变
5、需要经常添加新操作
6、算法涉及对象结构的多个类,但是需要在一个位置管理它
7、算法需要跨越几个独立的类层次结构

优点

1、增加新的操作很容易,即增加一个新的访问者就可以了
2、符合开闭原则

缺点

1、增加新的数据结构比较困难
2、具体元素变更比较麻烦

代码示例

image.png
汽车元素

public interface CarElement {
    void accept(CarElementVisitor visitor);
}

汽车元素访问者

public interface CarElementVisitor {
    void visit(Body body);
    void visit(Car car);
    void visit(Engine engine);
    void visit(Wheel wheel);
}

车身

public class Body implements CarElement{
    @Override
    public void accept(CarElementVisitor visitor) {
        visitor.visit(this);
    }
}

车轮

public class Wheel implements CarElement {
    private final String name;
    public Wheel(final String name) {
        this.name = name;
    }
    public String getName() {
        return name;
    }
    @Override
    public void accept(CarElementVisitor visitor) {
        visitor.visit(this);
    }
}

引擎

public class Engine implements CarElement{
    @Override
    public void accept(CarElementVisitor visitor) {
        visitor.visit(this);
    }
}

汽车

public class Car implements CarElement{
    private List<CarElement> elements;
    public Car() {
        this.elements = new ArrayList<>();
        this.elements.add(new Wheel("前左"));
        this.elements.add(new Wheel("前右"));
        this.elements.add(new Wheel("后左"));
        this.elements.add(new Wheel("后右"));
        this.elements.add(new Body());
        this.elements.add(new Engine());
    }
    @Override
    public void accept(CarElementVisitor visitor) {
        for (CarElement element : elements) {
            element.accept(visitor);
        }
        visitor.visit(this);
    }
}

启动汽车访问者

public class CarElementDoVisitor implements CarElementVisitor{
    @Override
    public void visit(Body body) {
        System.out.println("移动车身");
    }
    @Override
    public void visit(Car car) {
        System.out.println("启动车子");
    }
    @Override
    public void visit(Wheel wheel) {
        System.out.println("启动我的 " + wheel.getName() + " 车轮");
    }
    @Override
    public void visit(Engine engine) {
        System.out.println("开启引擎");
    }
}

打印汽车访问者

public class CarElementPrintVisitor implements CarElementVisitor{
    @Override
    public void visit(Body body) {
        System.out.println("访问车身");
    }
    @Override
    public void visit(Car car) {
        System.out.println("访问汽车");
    }
    @Override
    public void visit(Engine engine) {
        System.out.println("访问引擎");
    }
    @Override
    public void visit(Wheel wheel) {
        System.out.println("访问 " + wheel.getName() + " 车轮");
    }
}

测试类

public class VisitorTest {
    public static void main(String[] args) {
        Car car = new Car();
        car.accept(new CarElementPrintVisitor());
        car.accept(new CarElementDoVisitor());
    }
}

输出结果为:

访问 前左 车轮
访问 前右 车轮
访问 后左 车轮
访问 后右 车轮
访问车身
访问引擎
访问汽车
启动我的 前左 车轮
启动我的 前右 车轮
启动我的 后左 车轮
启动我的 后右 车轮
移动车身
开启引擎
启动车子

上面示例源码

源码分析

jdk中应用

FileVisitor从名字可以看出是一个访问者,可以遍历文件的一些属性。
image.png

spring中应用

BeanDefinitionVisitor可以遍历一些bean的属性
image.png

也可以关注我的公众号:程序之声
图片
关注公众号,领取更多资源

本文为博主原创文章,未经博主允许不得转载。

评论

发表评论