Design Pattern | Visitor Pattern 访问者模式
by Botao Xiao
访问者模式是一种将数据操作与数据结构分离的设计模式
访问者模式中的角色
- Visitor: 接口或者抽象类,它定义了对每一个元素(Element)访问的行为,它的参数就是可以访问的元素,它的方法数理论上来讲与元素个数是一样的,因此,访问者模式要求元素的类族要稳定,如果经常添加、移除元素类,必然会导致频繁地修改Visitor接口,如果这样则不适合使用访问者模式。
- ConcreteVisitor1、ConcreteVisitor2:具体的访问类,它需要给出对每一个元素类访问时所产生的具体行为。
- Element:元素接口或者抽象类,它定义了一个接受访问者的方法(Accept),其意义是指每一个元素都要可以被访问者访问。
- ConcreteElementA、ConcreteElementB:具体的元素类,它提供接受访问方法的具体实现,而这个具体的实现,通常情况下是使用访问者提供的访问该元素类的方法。
- 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(); } }
总结
- 一种解耦的方法,对访问者和被访问者都进行了解耦。
- 非常不适合经常添加修改的数据结构。
Reference
Subscribe via RSS