狐言不胡言

导航

由电脑专卖系统引发的Java设计模式:访问者模式

定义

访问者模式是对象的行为型模式,它的目的是封装一些施加于某些数据结构元素之上的操作,一旦这些操作需要修改的话,接收这个操作的数据结构则可以保持不变

意图

将数据结构与数据操作分离

解决问题

稳定的数据结构和易变的操作耦合问题

何时使用

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

优缺点

优点:

  • 使得增加新的操作很容易
  • 将有关的行为集中到一个访问者对象中,而不是分散到一个个的节点类中
  • 可以跨过几个类的等级结构访问属于不同的等级结构的成员类

缺点:

  • 增加新的节点类变的很困难
  • 破坏封装

结构

在这里插入图片描述
涉及的角色:

  • 抽象访问者(Visitor)角色:声明了一个或者多个访问操作,形成所有的具体元素角色必须实现的接口
  • 具体访问者(ConcreteVisitor)角色:实现抽象访问者角色所声明的接口,也就是抽象访问者所声明的各个访问操作
  • 抽象节点(Node)角色:声明一个接收操作,接收一个访问者对象作为一个参量
  • 具体节点(Node)角色:实现了抽象节点所规定的接收操作
  • 结构对象(ObjectStructure)角色:有下面的一些职责,可以遍历结构中的所有元素,如果需要,提供一个高层次接口让访问者对象可以访问每一个元素,如果需要,可以设计一个复合对象或者聚集,比如list或set

源码如下:
抽象访问者角色为每一个节点都提供了一个访问操作,并且接收相应的节点对象作为参量:

public interface Visitor {

    /** 对应于NodeA的访问操作 */
    void visit(NodeA nodeA);

    /** 对应于NodeB的访问操作 */
    void visit(NodeB nodeB);
}

下面是具体访问者角色:

public class VisitorA implements Visitor {

    /** 对应于NodeA的访问操作 */
    @Override
    public void visit(NodeA nodeA) {
        System.out.println(nodeA.operationA());
    }

    /** 对应于NodeB的访问操作 */
    @Override
    public void visit(NodeB nodeB) {
        System.out.println(nodeB.operationB());
    }
}
public class VisitorB implements Visitor {

    /** 对应于NodeA的访问操作 */
    @Override
    public void visit(NodeA nodeA) {
        System.out.println(nodeA.operationA());
    }

    /** 对应于NodeB的访问操作 */
    @Override
    public void visit(NodeB nodeB) {
        System.out.println(nodeB.operationB());
    }
}

抽象节点声明了一个接收操作:

public abstract class Node {

    /** 接收操作 */
    public abstract void accept(Visitor visitor);
}

具体节点:

public class NodeA extends Node {

    /** 接收操作 */
    @Override
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }

    /** NodeA特有的商业方法 */
    public String operationA() {
        return "NodeA被访问了";
    }
}

    /** 接收操作 */
    @Override
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }

    /** NodeB特有的商业方法 */
    public String operationB() {
        return "NodeB被访问了";
    }
}

结构对象角色,含有一个聚集,并且向外界提供了一个add方法作为对聚集的管理操作,通过调用这个方法,可以动态的增加一个新的节点:

public class ObjectStructure {

    private List<Node> nodes;

    private Node node;


    public ObjectStructure() {
        nodes = new ArrayList<>();
    }

    /** 执行访问操作 */
    public void action(Visitor visitor) {
        for (Node n : nodes) {
            n.accept(visitor);
        }
    }

    public void add(Node node) {
        nodes.add(node);
    }
}

客户端:

public class Client {

    private static ObjectStructure structure;

    private static Visitor visitor;

    public static void main(String[] args) {
        //创建一个结构对象
        structure = new ObjectStructure();
        //给结构增加一个节点
        structure.add(new NodeA());
        //给结构增加一个节点
        structure.add(new NodeB());
        //创建一个新的访问者
        visitor = new VisitorA();
        //让访问者访问结构
        structure.action(visitor);
    }
}

在这里插入图片描述

电脑专卖系统

这个电脑专卖店既可以卖组装好的电脑,也可以卖电脑零件,比如CPU、主板、机箱等,也可以卖半成品,比如集成主板等,每一种零件都有自己的价格

下面先定义了一个抽象访问者角色,声明了所有的访问方法:

public interface Visitor {

    /** 主板访问操作 */
    void visitMainBoard(MainBoard mainBoard);

    /** 硬盘访问操作 */
    void visitHardDisk(HardDisk disk);

    /** cpu访问操作 */
    void visitCpu(Cpu cpu);

    /** 机箱访问操作 */
    void visitCase(Case ce);

    /** 集成主板访问操作 */
    void visitIntegratedBoard(IntegratedBoard board);

    /** 组装电脑访问操作 */
    void visitPc(Pc pc);
}

具体访问者角色,用来计算各个零件加在一起的价格:

public class PriceVisitor implements Visitor {

    private double total;

    public PriceVisitor() {
        total = 0.0;
    }

    /** 商业方法 */
    public double value() {
        return total;
    }

    @Override
    public void visitMainBoard(MainBoard mainBoard) {
        total += mainBoard.price();
    }

    @Override
    public void visitHardDisk(HardDisk disk) {
        total += disk.price();
    }

    @Override
    public void visitCpu(Cpu cpu) {
        total += cpu.price();
    }

    @Override
    public void visitCase(Case ce) {
        total += ce.price();
    }

    @Override
    public void visitIntegratedBoard(IntegratedBoard board) {
        total += board.price();
    }

    @Override
    public void visitPc(Pc pc) {
        total += pc.price();
    }
}

下面是具体访问者角色,用来管理各个零件:

public class InventoryVisitor implements Visitor {

    private Vector vector;

    public InventoryVisitor() {
        vector = new Vector();
    }

    /** 商业方法 */
    public int size() {
        return vector.size();
    }

    @Override
    public void visitMainBoard(MainBoard mainBoard) {
        vector.add(mainBoard);
    }

    @Override
    public void visitHardDisk(HardDisk disk) {
        vector.add(disk);
    }

    @Override
    public void visitCpu(Cpu cpu) {
        vector.add(cpu);
    }

    @Override
    public void visitCase(Case ce) {
        vector.add(ce);
    }

    @Override
    public void visitIntegratedBoard(IntegratedBoard board) {
        vector.add(board);
    }

    @Override
    public void visitPc(Pc pc) {
        vector.add(pc);
    }
}

抽象节点角色,声明一个接收方法:

public abstract class Equipment {

    /** 接收方法 */
    public abstract void accept(Visitor visitor);

    /** 价格 */
    public abstract double price();
}

具体节点角色:

public class MainBoard extends Equipment {
    @Override
    public void accept(Visitor visitor) {
        System.out.println("主板被访问了");
        visitor.visitMainBoard(this);
    }

    @Override
    public double price() {
        return 100.0;
    }
}
public class HardDisk extends Equipment {
    @Override
    public void accept(Visitor visitor) {
        System.out.println("硬盘被访问了");
        visitor.visitHardDisk(this);
    }

    @Override
    public double price() {
        return 200.0;
    }
}
public class Cpu extends Equipment {
    @Override
    public void accept(Visitor visitor) {
        System.out.println("CPU被访问了");
        visitor.visitCpu(this);
    }

    @Override
    public double price() {
        return 800.0;
    }
}
public class Case extends Equipment {
    @Override
    public void accept(Visitor visitor) {
        System.out.println("机箱被访问了");
        visitor.visitCase(this);
    }

    @Override
    public double price() {
        return 30.0;
    }
}

下面是复合节点:

public class Composite extends Equipment {

    private Vector vector = new Vector();

    @Override
    public void accept(Visitor visitor) {
        for (int i = 0; i < vector.size(); i++) {
            ((Equipment)vector.get(i)).accept(visitor);
        }
    }

    @Override
    public double price() {
        double total = 0;
        for (int i=0; i<vector.size(); i++) {
            total += ((Equipment)vector.get(i)).price();
        }
        return total;
    }

    public void add(Equipment equipment) {
        vector.add(equipment);
    }
}
public class IntegratedBoard extends Composite {

    public IntegratedBoard() {
        super.add(new MainBoard());
        super.add(new Cpu());
    }

    @Override
    public void accept(Visitor visitor) {
        System.out.println("集成主板被访问了");
        super.accept(visitor);
    }
}
public class Pc extends Composite {

    public Pc() {
        super.add(new IntegratedBoard());
        super.add(new HardDisk());
        super.add(new Case());
    }

    @Override
    public void accept(Visitor visitor) {
        System.out.println("组装电脑被访问了");
        super.accept(visitor);
    }
}

客户端:

public class Client {

    private static PriceVisitor priceVisitor;

    private static InventoryVisitor inventoryVisitor;

    private static Equipment equipment;

    public static void main(String[] args) {
        equipment = new Pc();
        priceVisitor = new PriceVisitor();
        equipment.accept(priceVisitor);
        System.out.println("价格:" + priceVisitor.value());
        inventoryVisitor = new InventoryVisitor();
        equipment.accept(inventoryVisitor);
        System.out.println("零件数:" + inventoryVisitor.size());
    }
}

在这里插入图片描述

posted on 2021-04-17 10:58  狐言不胡言  阅读(63)  评论(0编辑  收藏  举报