设计模式之访问者模式

80 阅读2分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第28天,点击查看活动详情

简介

访问者模式的定义:

表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变各元素类的前提下定义作用于这些元素的新操作。

访问者模式的定义也是比较抽象,我们也不必过多纠结。访问者模式使用的场景相对比较少,实在不行,大家记住我下面的例子即可。

由于访问者模式涉及到的角色比较多,我们在这里还是针对每个角色做一个简单的梳理:

  • Visitor(抽象的访问者定义):作用是为每个元素定义一个访问的方法
  • ConcreteVisitor(具体的访问者实现):实现抽象类Visitor,实现各个对各个元素的访问
  • Element(抽象的元素):声明一个accept访问,用于接受Visitor的访问
  • ConcreteElement(具体的抽象元素实现):实现Element,实现accept方法
  • ObjectStructure:用于存放所有的元素,并提供遍历所有元素的方法

案例

我们通过老师访问学生的各科试卷为场景来实现一个访问者模式例子

首先我们定义一个抽象的访问者,其中有2个方法,一个是访问数据试卷的方法定义,一个访问英语试卷的方法定义

public abstract class Visitor {
    abstract void visitMathPaper(MathPaper mathPaper);
    abstract void visitEnglishPaper(EnglishPaper englishPaper);
}

然后定义一个真实的访问类,老师访问类,分别重写访问数据试卷和英语试卷的方法

public class TeacherVisitor extends Visitor {
    @Override
    void visitMathPaper(MathPaper mathPaper) {
        System.out.println("visit mathpaper");
    }
    @Override
    void visitEnglishPaper(EnglishPaper englishPaper) {
        System.out.println("visit englishpaper");
    }
}

定义抽象的试卷,定义接受访问的accept方法

public abstract class Paper {
    abstract void accept(Visitor visitor);
}

分别定义一个数学试卷和英语试卷,重写accept方法

public class MathPaper extends Paper {
    @Override
    void accept(Visitor visitor) {
        visitor.visitMathPaper(this);
    }
}
public class EnglishPaper extends Paper {
    @Override
    void accept(Visitor visitor) {
        visitor.visitEnglishPaper(this);
    }
}

定义一个试卷的访问情况报表类,模拟元素的保存和元素的遍历

public class PaperReport {
    private List<Paper> list = new ArrayList();
    public PaperReport() {
        this.list.add(new MathPaper());
        this.list.add(new EnglishPaper());
    }
    public void show(Visitor visitor) {
        list.forEach(e -> e.accept(visitor));
    }
}

测试类中我们看到输出结果成功地访问了数学试卷和英语试卷

public class App {
    public static void main(String[] args) {
        TeacherVisitor teacherVisitor = new TeacherVisitor();
        PaperReport paperReport = new PaperReport();
        paperReport.show(teacherVisitor);
    }
}

总结

访问者模式适合元素数量相对比较固定,不会改变的场景,这种情况下我们新增访问者是很方便的,比如上文我们可以新增一个家长访问者,而不用去改变任何元素。