当前位置: 代码迷 >> 综合 >> 设计模式-访问者模式(Visitor Pattern)
  详细解决方案

设计模式-访问者模式(Visitor Pattern)

热度:73   发布时间:2023-12-01 20:26:17.0

推荐:Java设计模式汇总

访问者模式

定义
将作用于某种数据结构中的各元素的操作分离出来封装成独立的类,使其在不改变数据结构的前提下可以添加作用于这些元素的新的操作,为数据结构中的每个元素提供多种访问方式,它将对数据的操作与数据结构进行分离。

类型
行为型。

UML类图
在这里插入图片描述

角色

  • 访问者(Visitor)角色 :接口或抽象类,它定义了对每一个元素(Element)访问的接口。
  • 具体访问者(ConcreteVisitor)角色 :具体的访问者,它需要实现对每一个元素类访问时所产生的具体行为 。
  • 元素(Element)角色 :接口或抽象类,它定义了一个接受访问的方法accept()
  • 具体元素(ConcreteElement)角色 :它提供接受访问方法的具体实现,而这个具体的实现,通常情况下是使用访问者提供的访问该元素类的方法。
  • 数据结构(ObjectStructure)角色 :定义程序当中所使用的数据结构,对象结构是一个抽象表述,它内部管理了元素集合,并且可以迭代这些元素供访问者访问。

例子
慕课网有免费课和实战课,每个用户可以相当于一个访问者,访问这些课程信息。
而慕课网的工作人员也可以相当于一个访问者,不过这个访问者还可以得到这些课程所产生的利润,为了简单,这个就不实现了,只是为了说明访问者模式。

IVisitor接口(访问者角色),定义了两个接口,用来访问两种不同类型的课程(免费课和实战课)。
这里不符合依赖倒置原则,抽象层依赖了具体层,这是访问者模式的一个缺点。

package com.kaven.design.pattern.behavioral.visitor;public interface IVisitor {
    void visit(FreeCourse freeCourse);void visit(CodingCourse codingCourse);
}

Course类(元素角色),定义了一个接受访问的方法accept()

package com.kaven.design.pattern.behavioral.visitor;public abstract class Course {
    private String name;public String getName() {
    return name;}public void setName(String name) {
    this.name = name;}public abstract void accept(IVisitor visitor);
}

FreeCourse类(具体元素角色),免费课程类。

package com.kaven.design.pattern.behavioral.visitor;public class FreeCourse extends Course {
    public void accept(IVisitor visitor) {
    visitor.visit(this);}
}

CodingCourse类(具体元素角色),实战课程类,实战课程有一个价格属性。

package com.kaven.design.pattern.behavioral.visitor;public class CodingCourse extends Course {
    private int price;public int getPrice() {
    return price;}public void setPrice(int price) {
    this.price = price;}public void accept(IVisitor visitor) {
    visitor.visit(this);}
}

Visitor类(具体访问者角色),实现了对每一个元素类访问时所产生的具体行为 。

package com.kaven.design.pattern.behavioral.visitor;public class Visitor implements IVisitor{
    public void visit(FreeCourse freeCourse) {
    System.out.println("免费课程:"+freeCourse.getName());}public void visit(CodingCourse codingCourse) {
    System.out.println("实战课程:"+codingCourse.getName()+" 价格:"+codingCourse.getPrice());}
}

数据结构角色就不写了,在应用层代码中用List和一些操作代替了。

应用层代码:

package com.kaven.design.pattern.behavioral.visitor;import java.util.ArrayList;
import java.util.List;public class Test {
    public static void main(String[] args) {
    List<Course> courseList = new ArrayList<Course>();FreeCourse freeCourse = new FreeCourse();freeCourse.setName("SpringMVC数据绑定");CodingCourse codingCourse = new CodingCourse();codingCourse.setName("Java设计模式");codingCourse.setPrice(299);courseList.add(freeCourse);courseList.add(codingCourse);for(Course course : courseList){
    course.accept(new Visitor());}}
}

输出:

免费课程:SpringMVC数据绑定
实战课程:Java设计模式 价格:299

这里便完成了一个简单的访问者模式的例子。

适用场景

  • 对象结构中对象对应的类很少改变,但经常需要在此对象结构上定义新的操作。
  • 需要对一个对象结构中的对象进行很多不同的并且不相关的操作,并且需要避免让这些操作"污染"这些对象的类,也不希望在增加新操作时修改这些类。

优点

  • 各个角色职责分离,符合单一职责原则。
  • 使得数据结构和作用于结构上的操作解耦,使得操作集合可以独立变化。
  • 优秀的扩展性。
  • 灵活性高。

缺点

  • 具体元素对访问者公布细节,违反了迪米特原则。
  • 具体元素变更时导致修改成本大。
  • 违反了依赖倒置原则,为了达到区别对待,而依赖了具体类,而不是抽象。

如果有说错的地方,请大家不吝赐教(记得留言哦~~~~)。

  相关解决方案