设计模式笔记_行为型_访问者模式

1. 访问者模式介绍

访问者模式(Visitor Pattern)是一种行为型设计模式,它允许你在不改变对象结构的前提下,定义作用于这些对象的新操作。访问者模式将操作的逻辑从对象结构中分离出来,使得你可以在运行时动态地添加新的操作。

类比场景: 想象一下,你有一个博物馆,里面有不同的展品(对象结构):绘画、雕塑等。当有不同的访客(访问者,比如艺术爱好者、学生等)来参观时,他们可能希望对展品进行不同的处理或观察(操作)。访问者模式就像是让这些访客带着自己的需求来参观博物馆,而博物馆本身无需改变展品的展示方式。当有新的访问者要进行新的操作时,只需要新增一个访问者即可。

结构组成:

  1. Visitor(访问者接口):定义访问者可以执行的操作;对每种元素类型都有一个方法。
  2. ConcreteVisitor(具体访问者):实现Visitor接口,定义每个元素的具体访问行为。
  3. Element(元素接口):被访问者接口,定义接受访问者的方法。
  4. ConcreteElement(具体元素):实现Element接口,具体定义接受访问者的行为。
  5. Object Structure:包含元素的集合,提供一个可以遍历这些元素的高层接口,并让访问者访问它们。

优缺点分析:

  • 优点
    • 新增操作方便:可以在不修改对象结构的情况下增加新的操作(通过新增visitor实现)。
    • 符合单一职责原则:将不同的操作分离到不同的访问者中。
    • 扩展性好:可以很方便地增加新的访问者。
  • 缺点
    • 对象结构必须稳定 :如果对象结构经常改变,维护成本会很高(每个visitor里定义了对所有元素的访问,如果元素发生改变,需要修改所有visitor)。
    • 具体元素更复杂:每个具体元素都需要实现接受访问者的方法。
    • 可能导致类爆炸:如果元素和访问者种类很多,会导致类数量激增。

适用场景:

  • 当对象结构较为稳定,且需要在此结构上定义新的操作时。
  • 当需要对一个对象结构中的对象进行很多不同且不相关的操作时。

2. 代码演示

场景:学生和艺术爱好者(visitor)去博物馆(objectStructure)参观绘画和雕像(element),各类人行为不同。

Visitor(访问者接口):

java 复制代码
// Visitor接口:定义一个访问者可以执行的操作
// 包含了对所有具体元素的访问方法
public interface Visitor {
    void visit(Painting painting);
    void visit(Sculpture sculpture);
}

ConcreteVisitor(具体访问者):

java 复制代码
//具体访问者: 实现Visitor接口,用于定义某种操作
//艺术爱好者的行为
public class ArtLoverVisitor implements Visitor {
    @Override
    public void visit(Painting painting) {
        System.out.println("ArtLoverVisitor visit painting: " + painting.getName());
    }

    @Override
    public void visit(Sculpture sculpture) {
        System.out.println("ArtLoverVisitor visit sculpture: " + sculpture.getName());
    }
}

//学生的行为
public class StudentVisitor implements Visitor {
    @Override
    public void visit(Painting painting) {
        System.out.println("StudentVisitor visit painting: " + painting.getName());
    }

    @Override
    public void visit(Sculpture sculpture) {
        System.out.println("StudentVisitor visit sculpture: " + sculpture.getName());
    }
}

Element(元素接口)

java 复制代码
// Element接口:被访问对象,定义接受访问者的接口
public interface Exhibit {
    void accept(Visitor visitor);
}

ConcreteElement(具体元素):

java 复制代码
// 具体元素: 实现Element接口,定义接受访问者的操作
// 绘画
public class Painting implements Exhibit {
    private String name;

    public Painting(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

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

//雕像
public class Sculpture implements Exhibit {
    private String name;

    public Sculpture(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

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

Object Structure:

java 复制代码
// ObjectStructure:维护元素对象列表,并提供高层方法来遍历操作这些对象
public class Museum {
    private List<Exhibit> exhibits = new ArrayList<>();

    public void addExhibit(Exhibit exhibit) {
        exhibits.add(exhibit);
    }

    public void showExhibits(Visitor visitor) {
        for (Exhibit exhibit : exhibits) {
            exhibit.accept(visitor);
        }
    }
}

客户端:

java 复制代码
public class VisitorClientDemo {
    public static void main(String[] args) {
        Museum museum = new Museum();
        museum.addExhibit(new Sculpture("The Thinker"));
        museum.addExhibit(new Painting("Starry Night"));

        Visitor visitor1 = new ArtLoverVisitor();
        museum.showExhibits(visitor1);

        Visitor visitor2 = new StudentVisitor();
        museum.showExhibits(visitor2);
    }
}

对应的类图:

扩展:

上述示例中,将操作(学生/艺术爱好者的行为) 从对象结构(绘画/雕塑等展览)中分离出来了,后续若需添加新的操作(历史专家的行为),只需要新增对应的visitor(HistorianVisitor) 即可。

相关推荐
User_芊芊君子5 小时前
【Java】设计模式——单例、工厂、代理模式
java·设计模式·代理模式
大筒木老辈子6 小时前
Linux笔记---协议定制与序列化/反序列化
网络·笔记
草莓熊Lotso6 小时前
【C++】递归与迭代:两种编程范式的对比与实践
c语言·开发语言·c++·经验分享·笔记·其他
YA3338 小时前
java设计模式二、工厂
java·开发语言·设计模式
我爱挣钱我也要早睡!9 小时前
Java 复习笔记
java·开发语言·笔记
汇能感知13 小时前
摄像头模块在运动相机中的特殊应用
经验分享·笔记·科技
阿巴Jun14 小时前
【数学】线性代数知识点总结
笔记·线性代数·矩阵
茯苓gao14 小时前
STM32G4 速度环开环,电流环闭环 IF模式建模
笔记·stm32·单片机·嵌入式硬件·学习
是誰萆微了承諾14 小时前
【golang学习笔记 gin 】1.2 redis 的使用
笔记·学习·golang
DKPT15 小时前
Java内存区域与内存溢出
java·开发语言·jvm·笔记·学习