访问者模式是一种将数据操作与数据结构分离的设计模式

访问者模式中的角色

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

访问者模式的实现

  • Visitor的接口
    public interface AccountBillViewer {	//针对每一个element对象都定义了一个访问方法
      public void view(ConsumerBill bill);
      public void view(IncomeBill bill);
    }
    
  • Visitor的实现类
    public class Boss implements AccountBillViewer {	//在Viewer的实现类中,定义了对每一个Element的实现方法。
      private double totalIncome;
      private double totalConsume;
      @Override
      public void view(ConsumerBill bill) {
          totalConsume += bill.getAmount();
      }
      @Override
      public void view(IncomeBill bill) {
          this.totalIncome += bill.getAmount();
      }
      public double getTotalConsume() {
          System.out.println("Boss: spend " + this.totalConsume + " dollars");
          return totalConsume;
      }
      public double getTotalIncome() {
          System.out.println("Boss: get " + this.totalIncome + " dollars");
          return totalIncome;
      }
    }
    public class Accounter implements AccountBillViewer {
      @Override
      public void view(ConsumerBill bill) {
          if(bill.getItem().equals("salary"))
              System.out.println("Check comsume...");
      }
      @Override
      public void view(IncomeBill bill) {
          if(bill.getItem().equals("income"))
              System.out.println("Check Income...");
      }
    }
    
  • Element的抽象类
    public interface Bill {	//Element的抽象类
      public void accept(AccountBillViewer viewer);	//在抽象类中,定义了accept方法,在方法中对本身进行调用,实现方法
    }
    
  • Element的实现类
    public class ConsumerBill implements Bill {
      private Double amount;
      private String item;
      public String getItem() {
          return item;
      }
      public Double getAmount() {
          return amount;
      }
      public ConsumerBill(Double amount, String item) {
          this.amount = amount;
          this.item = item;
      }
      @Override
      public void accept(AccountBillViewer viewer) {	//在Element对象中,通过viewer本身对当前的Element类进行调用。
          viewer.view(this);
      }
    }
    public class IncomeBill implements Bill {
      private Double amount;
      private String item;
      public Double getAmount() {
          return amount;
      }
      public String getItem() {
          return item;
      }
      public IncomeBill(Double amount, String item) {
          this.amount = amount;
          this.item = item;
      }
      @Override
      public void accept(AccountBillViewer viewer) {
          viewer.view(this);
      }
    }
    
  • ObjectStructure
    public class AccountBook {
      private List<Bill> billList = new ArrayList<>();	//通过一个数据结构承载了所有的对象。
      public void addBill(Bill bill){	//向数据结构中加入element的方法。
          this.billList.add(bill);
      }
      public void show(AccountBillViewer viewer){
          for(Bill bill : billList){	//对对象进行访问。
              bill.accept(viewer);
          }
      }
      public static void main(String[] args) {
          AccountBook accountBook = new AccountBook();
          accountBook.addBill(new IncomeBill(100d, "a"));
          accountBook.addBill(new IncomeBill(200d, "b"));
          accountBook.addBill(new ConsumerBill(100d, "c"));
          accountBook.addBill(new ConsumerBill(200d, "d"));
          AccountBillViewer boss = new Boss();
          AccountBillViewer accounter = new Accounter();
          accountBook.show(boss);
          accountBook.show(accounter);
          ((Boss)boss).getTotalConsume();
          ((Boss)boss).getTotalIncome();
      }
    }
    

总结

  1. 一种解耦的方法,对访问者和被访问者都进行了解耦。
  2. 非常不适合经常添加修改的数据结构。

Reference

  1. 设计模式学习之访问者模式