访问者模式
访问者模式:表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变各元素类的前提下定义作用于这些元素的新操作。
访问者涉及到的角色:
1.Visitor 抽象访问者角色,为该对象结构中具体元素角色声明一个访问操作接口。该操作接口的名字和参数标识了发送访问请求给具体访问者的具体元素角色,这样访问者就可以通过该元素角色的特定接口直接访问它。
2.ConcreteVisitor.具体访问者角色,实现Visitor声明的接口。
3.Element 定义一个接受访问操作(accept()),它以一个访问者(Visitor)作为参数。
4.ConcreteElement 具体元素,实现了抽象元素(Element)所定义的接受操作接口。
5.ObjectStructure 结构对象角色,这是使用访问者模式必备的角色。它具备以下特性:能枚举它的元素;可以提供一个高层接口以允许访问者访问它的元素;如有需要,可以设计成一个复合对象或者一个聚集(如一个列表或无序集合)。
以商店的销售记录为例,每条记录记录了所卖商品的名字、数量和价格,对于老板这个访问者关系的是总的销售额,而对于采购员这个访问者则关心的是各个商品的销售数量。此时我们就可以使用访问者模式,将数据操作与数据结构分离,从而使得不同的访问者类针对对象结构来完成不同的操作。类图如下:
下面是简单demo
package visitor; public abstract class Bill { abstract void accept(Visitor visitor); }
package visitor; public class SailBill extends Bill { private Long count; private Long price; private String name; public Long getCount() { return count; } public void setCount(Long count) { this.count = count; } public Long getPrice() { return price; } public void setPrice(Long price) { this.price = price; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public void accept(Visitor visitor) { visitor.visitBill(this); } public SailBill(Long count, Long price, String name) { super(); this.count = count; this.price = price; this.name = name; } }
package visitor; public interface Visitor { void visitBill(SailBill bill); }
package visitor; public class Boss implements Visitor { private double income; @Override public void visitBill(SailBill bill) { income += bill.getCount()*bill.getPrice(); } public double getIncome() { return income; } public void setIncome(double income) { this.income = income; } }
package visitor; import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; public class Buyer implements Visitor { private Map<String,Long> salesVolume = new HashMap<String, Long>(); @Override public void visitBill(SailBill bill) { if(salesVolume.get(bill.getName())==null) { salesVolume.put(bill.getName(), bill.getCount()); }else { salesVolume.put(bill.getName(), salesVolume.get(bill.getName()) + bill.getCount()); } } public void display() { for (Entry<String,Long> entry : salesVolume.entrySet()) { System.out.println(entry.getKey() +"-----" + entry.getValue()); } } }
package visitor; import java.util.ArrayList; import java.util.List; public class ObjectStructure { private List<Bill> list = new ArrayList<>(); public void addBill(Bill bill) { list.add(bill); } public void show (Visitor visitor) { for (Bill bill : list) { bill.accept(visitor); } } }
执行测试代码如下
访问者模式的使用场景:
1、 一个对象结构包含很多类对象,它们有不同的接口,而你想对这些对象实施一些依赖于其具体类的操作。
2、 需要对一个对象结构中的对象进行很多不同的并且不相关的操作,而你想避免让这些操作“污染”这些对象的类。Visitor模式使得你可以将相关的操作集中起来 定义在一个类
3、 当该对象结构被很多应用共享时,用Visitor模式让每个应用仅包含需要用到的操作。
4、定义对象结构的类很少改变,但经常需要在此结构上定义新的操作。改变对象结构类需要重定义对所有访问者的接口,这可能需要很大的代价。如果对象结构类经常改变,那么可能还是在这些类中定义这些操作较好。