6

HeadFirst设计模式二十四【访问者模式】

 4 years ago
source link: http://bboyjing.github.io/2020/01/15/HeadFirst%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F%E4%BA%8C%E5%8D%81%E5%9B%9B%E3%80%90%E8%AE%BF%E9%97%AE%E8%80%85%E6%A8%A1%E5%BC%8F%E3%80%91/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

HeadFirst设计模式二十四【访问者模式】

2020-01-15

| 设计模式

访问者模式的目的是封装一些施加于某种数据结构元素之上的操作。一旦这些操作需要修改的话,接受这个操作的数据结构则可以保持不变。上面的术语不是很好理解,我们来看看下面的场景,就会觉得很熟悉了。

假设有下面现在需要建造一辆汽车,简单的实现方式如下:

  1. 创建汽车部件抽象接口

    public interface CarComponent {
    public void printMessage();
  2. 创建轮胎部件

    public class Wheel implements CarComponent {
    @Override
    public void printMessage() {
    System.out.println("This is a wheel");
    * 这时Wheel和Engine不同的方法
    public void doWheel() {
    System.out.println("Checking wheel...");
  3. 创建引擎部件

    public class Engine implements CarComponent {
    @Override
    public void printMessage() {
    System.out.println("This is a engine");
    * 这时Wheel和Engine不同的方法
    public void doEngine() {
    System.out.println("Testing this engine...");
  4. public class Car {
    private List<CarComponent> components;
    public Car() {
    this.components = new ArrayList<>();
    * 这里需要根据CarComponent具体的类型去做不同的事情
    public void setComponent(CarComponent component) {
    components.add(component);
    if (component instanceof Wheel) {
    ((Wheel) component).doWheel();
    } else {
    ((Engine) component).doEngine();

instanceof虽然简单,但是当零件特别多的时候,要写一堆的if/else,很不友好。下面就来学习访问者模式是如何解决这个问题的。

访问者模式所涉及的角色如下:

  • 抽象访问者(Visitor):声明了一个或多个访问操作。
  • 具体访问者(Concrete Visitor):实现抽象访问者所声明的接口,也就是抽象访问者所声明的各个访问操作。
  • 抽象元素(Element):声明一个接受操作,接受一个访问者对象作为参数
  • 具体的元素(ConcreteElement):实现了抽象元素所规定的接受操作。
  • 结构对象(ObjectStructure):有如下职责,可以遍历结构中的所有元素;如果需要,提供一个高层次的接口让访问者对象可以访问每一个元素;如果需要,可以设计成一个复合对象或者一个聚合,如List或Set。

结合代码来理解如上几种角色:

  1. 创建抽象访问者

    * 因为有四个元素要访问,所以定义了四个访问方法
    public interface Visitor {
    void visit(final Body body);
    void visit(final Car car);
    void visit(final Engine Engine);
    void visit(final Wheel wheel);
  2. 创建抽象元素接口

    public interface Element {
    * 接收一个观察者对象
    public void accept(final Visitor visitor);
  3. 创建真实汽车部件元素:Body、Engine、Wheel

    public class Body implements Element {
    @Override
    public void accept(Visitor visitor) {
    visitor.visit(this);
    public class Engine implements Element {
    @Override
    public void accept(Visitor visitor) {
    visitor.visit(this);
    public class Wheel implements Element {
    private String name;
    public Wheel(String name) {
    this.name = name;
    public String getName() {
    return name;
    @Override
    public void accept(Visitor visitor) {
    visitor.visit(this);
  4. 创建汽车元素

    public class Car implements Element {
    private List<Element> elements;
    public Car() {
    this.elements = new ArrayList<>();
    this.elements.add(new Wheel("front left"));
    this.elements.add(new Wheel("front right"));
    this.elements.add(new Wheel("back left"));
    this.elements.add(new Wheel("back right"));
    this.elements.add(new Engine());
    this.elements.add(new Body());
    @Override
    public void accept(Visitor visitor) {
    for (Element element : elements) {
    element.accept(visitor);
    visitor.visit(this);
  5. 创建具体的Do访问者

    public class DoVisitor implements Visitor {
    @Override
    public void visit(Body body) {
    System.out.println("Moving my body");
    @Override
    public void visit(Car car) {
    System.out.println("Starting my car");
    @Override
    public void visit(Engine engine) {
    System.out.println("Starting my engine");
    @Override
    public void visit(Wheel wheel) {
    System.out.println("Kicking my " + wheel.getName() + " wheel");
  6. 创建具体的Print访问者

    public class PrintVisitor implements Visitor {
    @Override
    public void visit(Body body) {
    System.out.println("Visiting body");
    @Override
    public void visit(Car car) {
    System.out.println("Visiting car");
    @Override
    public void visit(Engine engine) {
    System.out.println("Visiting engine");
    @Override
    public void visit(Wheel wheel) {
    System.out.println("Visiting " + wheel.getName() + " wheel");
  7. public class Test {
    public static void main(String[] args) {
    final Element car = new Car();
    car.accept(new DoVisitor());
    car.accept(new PrintVisitor());

这个模式的核心在于,具体的元素接收一个观察者,观察者里则定义了访问所有元素的方法。正是因为,把所有元素的访问方式都交给了访问者,所以消除了之前的if/else硬编码。本章节就到这里了,同时设计模式这个系列的学习也告一段落了。整个学习过程使用了两本书:《Head First设计模式》和《Java与模式》,向作者致敬。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK