设计模式-访问者模式(二十)

  • 目的是:

封装一些施加于某种数据结构元素之上的操作,一旦这些操作改变,接受这个操作的数据结构则可以保持不变

何时使用:需要对一个对象结构中的对象进行很多不同的并且不相关的操作,而需要避免让这些操作"污染"这些对象的类,使用访问者模式将这些封装到类中

Problem:如何针对保存有不同类型对象的聚集采取某种操作?
用if?

image.png

访问者模式适用于 数据结构不确定的情况,它把数据结构和操作之间的耦合解脱开。

  • 使用场景: 1、对象结构中对象对应的类很少改变(也就是Node很少改变),但经常需要在此对象结构上定义新的操作(也就是经常要增加Visitor)

  • 上类图:


    访问者角色.png
  • 优点:
    将有关的行为集中到一个访问者对象中,而不是分散到一个个节点类中,行为集中了,相关的操作状态(类似属性)也积累在自己的内部,而不是分散到很多对象中,这是有利于维护的.

  • 缺点:
    如果要增加一个新的节点都要在抽象访问者角色中增加一个新的抽象操作.

  • 代码示例:

  1. 定义一个访问者访问的接口类,抽象节点角色
/**
 * FileName :ComputerPart
 * Author :zengzhijun
 * Date : 2018/5/28 15:34
 * Description:
 */
package com.byedbl.visitor.sample2.entity;

import com.byedbl.visitor.sample2.visitor.ComputerPartVisitor;

public interface ComputerPart {
    public void accept(ComputerPartVisitor computerPartVisitor);
}

  1. 实现4个具体节点
/**
 * FileName :Keyboard
 * Author :zengzhijun
 * Date : 2018/5/28 15:34
 * Description:
 */
package com.byedbl.visitor.sample2.entity;

import com.byedbl.visitor.sample2.visitor.ComputerPartVisitor;

public class Keyboard  implements ComputerPart {

    @Override
    public void accept(ComputerPartVisitor computerPartVisitor) {
        computerPartVisitor.visit(this);
    }
}
/**
 * FileName :Monitor
 * Author :zengzhijun
 * Date : 2018/5/28 15:35
 * Description:
 */
package com.byedbl.visitor.sample2.entity;

import com.byedbl.visitor.sample2.visitor.ComputerPartVisitor;

public class Monitor  implements ComputerPart {

    @Override
    public void accept(ComputerPartVisitor computerPartVisitor) {
        computerPartVisitor.visit(this);
    }
}

/**
 * FileName :Mouse
 * Author :zengzhijun
 * Date : 2018/5/28 15:35
 * Description:
 */
package com.byedbl.visitor.sample2.entity;

import com.byedbl.visitor.sample2.visitor.ComputerPartVisitor;

public class Mouse  implements ComputerPart {

    @Override
    public void accept(ComputerPartVisitor computerPartVisitor) {
        computerPartVisitor.visit(this);
    }
}
/**
 * FileName :Computer
 * Author :zengzhijun
 * Date : 2018/5/28 15:35
 * Description:
 */
package com.byedbl.visitor.sample2.entity;

import com.byedbl.visitor.sample2.visitor.ComputerPartVisitor;

public class Computer implements ComputerPart {

    ComputerPart[] parts;

    public Computer(){
        parts = new ComputerPart[] {new Mouse(), new Keyboard(), new Monitor()};
    }


    @Override
    public void accept(ComputerPartVisitor computerPartVisitor) {
        for (int i = 0; i < parts.length; i++) {
            parts[i].accept(computerPartVisitor);
        }
        computerPartVisitor.visit(this);
    }
}

  1. 定义访问者抽象接口
/**
 * FileName :ComputerPartVisitor
 * Author :zengzhijun
 * Date : 2018/5/28 15:36
 * Description:
 */
package com.byedbl.visitor.sample2.visitor;

import com.byedbl.visitor.sample2.entity.Computer;
import com.byedbl.visitor.sample2.entity.Keyboard;
import com.byedbl.visitor.sample2.entity.Monitor;
import com.byedbl.visitor.sample2.entity.Mouse;

public interface ComputerPartVisitor {
    public void visit(Computer computer);
    public void visit(Mouse mouse);
    public void visit(Keyboard keyboard);
    public void visit(Monitor monitor);
}

  1. 实现访问者接口
/**
 * FileName :ComputerPartDisplayVisitor
 * Author :zengzhijun
 * Date : 2018/5/28 15:36
 * Description:
 */
package com.byedbl.visitor.sample2.visitor;

import com.byedbl.visitor.sample2.entity.Computer;
import com.byedbl.visitor.sample2.entity.Keyboard;
import com.byedbl.visitor.sample2.entity.Monitor;
import com.byedbl.visitor.sample2.entity.Mouse;

public class ComputerPartDisplayVisitor implements ComputerPartVisitor {

    @Override
    public void visit(Computer computer) {
        System.out.println("Displaying Computer.");
    }

    @Override
    public void visit(Mouse mouse) {
        System.out.println("Displaying Mouse.");
    }

    @Override
    public void visit(Keyboard keyboard) {
        System.out.println("Displaying Keyboard.");
    }

    @Override
    public void visit(Monitor monitor) {
        System.out.println("Displaying Monitor.");
    }
}

  1. 客户端用法
/**
 * FileName :VisitorPatternDemo
 * Author :zengzhijun
 * Date : 2018/5/28 15:36
 * Description:
 */
package com.byedbl.visitor.sample2;

import com.byedbl.visitor.sample2.entity.Computer;
import com.byedbl.visitor.sample2.entity.ComputerPart;
import com.byedbl.visitor.sample2.entity.Mouse;
import com.byedbl.visitor.sample2.visitor.ComputerPartDisplayVisitor;

/**
 *
 * 
 * 备受争议的访问者模式
 * 因为增加一个Node节点就要在Visitor节点中(这里是 ComputerPartVisitor)增加一个方法支持它
 * 如果已经实现了很多Visitor那不是很坑爹?当然在java8里面可以加一个默认的方法了,情况可能好一点
 * 但是还是不能掩盖其违反了开闭原则
 *
 * 但是作为实用主义来讲,只要管用,理论就可以先一边呆着去...
 * 毕竟像中国的代码,if else if 几百行 也不是没见过的
 *
 * @author : zengzhijun
 * @date : 2018/5/28 15:51
 **/
public class VisitorPatternDemo {

    public static void main(String[] args) {

        ComputerPart computer = new Computer();
        computer.accept(new ComputerPartDisplayVisitor());
        System.out.println("--------------");
        ComputerPart computerPart = new Mouse();
        computerPart.accept(new ComputerPartDisplayVisitor());
    }
}

这个例子很形象,电脑组件就这几个,但是不同的人用来干不同的事,也就是满足对象结构中对象对应的类很少改变(也就是Node很少改变),但经常需要在此对象结构上定义新的操作(也就是经常要增加Visitor)

你可能感兴趣的:(设计模式-访问者模式(二十))