访问者模式

定义

封装作用与某种数据结构(如List/Set/Map等)中的各元素的操作。它可以使你在不改变各元素的类的前提下,定义作用于这些元素的操作。但需要这些被操纵的元素相对稳定。

简而言之,就是专门有个对象来访问某种数据结构的元素,且不改变这些元素。使元素本身与操作分离。

访问者模式能把处理方法从数据结构中分离出来,并可以根据需要增加新的处理方法,且不用修改原来的程序代码与数据结构,这提高了程序的扩展性和灵活性。

类型

行为型

适用场景

  • 一个数据结构(如List/Set/Map等)包含很多类型对象
  • 数据结构与数据操作分离

优点

  • 扩展性好。增加新的操作很容易,即增加一个新的访问者。
  • 复用性好。可以通过访问者来定义整个对象结构通用的功能,从而提高系统的复用程度。
  • 灵活性好。访问者模式将数据结构与作用于结构上的操作解耦,使得操作集合可相对自由地演化而不影响系统的数据结构。
  • 符合单一职责原则。访问者模式把相关的行为封装在一起,构成一个访问者,使每一个访问者的功能都比较单一。

缺点

  • 增加新的数据结构困难
  • 具体元素变更比较麻烦,即被访问对象中的元素改变,那么访问者中定义的操作也要随之改变,违背了开闭原则。
  • 违反了依赖倒置原则。访问者模式依赖了具体类,而没有依赖抽象类。

UML类图

 

  • Visitor:接口或者抽象类,它定义了对每一个元素(Element)访问的行为,它的参数就是可以访问的元素,它的方法数理论上来讲与元素个数是一样的,因此,访问者模式要求元素的类族要稳定,如果经常添加、移除元素类,必然会导致频繁地修改Visitor接口,如果这样则不适合使用访问者模式。
  • ConcreteVisitorA、ConcreteVisitorB:具体的访问类,它需要给出对每一个元素类访问时的具体行为。
  • Element:、接口或者抽象类,它定义了一个接受访问者的方法(Accept),其意义是指每一个元素都要可以被访问者访问。
  • ConcreteElementA、ConcreteElementB:具体的元素类,它提供接受访问方法的具体实现,而这个具体的实现,通常情况下是使用访问者提供的访问该元素类的方法。
  • ObjectStructure:定义当中所说的对象结构,对象结构是一个抽象表述,它内部管理了元素集合,并且可以迭代这些元素供访问者访问。

 

代码实例

以访问免费课程和付费课程为例,下面是UML图:

  • Course(Element)
public abstract class Course {
    protected String name;

    public String getName() {
        return name;
    }

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

    public abstract void accept(Visitor visitor);
}
  • FreeCourse(ConcreteElement)
public class FreeCourse extends Course {

    public FreeCourse(String name) {
        super(name);
    }

    @Override
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }
}
  • PaidCourse(ConcreteElement)
public class PaidCourse extends Course {
    private String price;

    public PaidCourse(String name,String price) {
        super(name);
        this.price = price;
    }


    public String getPrice() {
        return price;
    }

    @Override
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }
}
  • Visitor
public interface Visitor {
    void visit(FreeCourse freeCourse);
    void visit(PaidCourse paidCourse);
}
  • CourseVisitor(ConcreteVisitor)
public class CourseVisitor implements Visitor {
    @Override
    public void visit(FreeCourse freeCourse) {
        System.out.println(freeCourse.getName());
    }

    @Override
    public void visit(PaidCourse paidCourse) {
        System.out.println(paidCourse.getName() + ":" + paidCourse.getPrice());
    }
}
  • CourseStructure(ObjectStructure)
public class CourseStructure {
    private List<Course> courses = new ArrayList<>();

    public void add(Course course){
        courses.add(course);
    }

    public void remove(Course course){
        courses.remove(course);
    }

    public void accept(Visitor visitor){
        for (Course course : courses){
            course.accept(visitor);
        }
    }
}

访问者意在针对不同的数据类型对象作出不同的行为。

访问者模式与其他模式

访问者模式本身在开发中使用的较少。一般会和迭代器模式和组合模式联用。

  • 迭代器模式。因为访问者模式中的ObjectStructure是一个包含元素角色的容器,当访问者遍历容器中的所有元素时,常常要用迭代器。
  • 组合模式。因为访问者模式中的Element可能是叶子对象或者是容器对象,如果元素对象包含容器对象,就必须用到组合模式。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值