访问者模式(visitor)
定义
表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。
UML图
角色
抽象访问者(Visitor)角色:声明了一个或者多个方法操作,形成所有的具体访问者角色必须实现的接口。
具体访问者(ConcreteVisitor)角色:实现抽象访问者所声明的接口,也就是抽象访问者所声明的各个访问操作。
抽象节点(Node)角色:声明一个接受操作,接受一个访问者对象作为一个参数。
具体节点(ConcreteNode)角色:实现了抽象节点所规定的接受操作。
结构对象(ObjectStructure)角色:有如下的责任,可以遍历结构中的所有元素;如果需要,提供一个高层次的接口让访问者对象可以访问每一个元素;如果需要,可以设计成一个复合对象或者一个聚集,如List或Set。
例子
抽象节点(Node)角色
package com.csdhsm.pattemdesign.visitor; /** * @Title: ItemElement.java * @Description: Element抽象类 * @author: Han * @date: 2016年7月2日 上午10:50:17 */ public interface ItemElement { public int accept(ShoppingCarVisitor vistor); }
具体实现节点
package com.csdhsm.pattemdesign.visitor; /** * @Title: Book.java * @Description: 具体实现类 * @author: Han * @date: 2016年7月2日 上午10:51:10 */ public class Book implements ItemElement { private int price; private String number; public Book(int price, String number) { this.price = price; this.number = number; } public int getPrice() { return price; } public String getNumber() { return number; } @Override public int accept(ShoppingCarVisitor vistor) { return vistor.visit(this); } }
package com.csdhsm.pattemdesign.visitor; /** * @Title: Fruit.java * @Description: 具体实现类 * @author: Han * @date: 2016年7月2日 上午10:51:31 */ public class Fruit implements ItemElement { private String name; private int price; public Fruit(String name, int price) { this.name = name; this.price = price; } public String getName() { return name; } public int getPrice() { return price; } @Override public int accept(ShoppingCarVisitor vistor) { return vistor.visit(this); } }
抽象访问者(Visitor)角色
package com.csdhsm.pattemdesign.visitor; /** * @Title: ShoppingCarVisitor.java * @Description: 抽象访问者 * @author: Han * @date: 2016年7月2日 上午10:51:51 */ public interface ShoppingCarVisitor { public int visit(Book book); public int visit(Fruit fruit); }
具体访问者(ConcreteVisitor)角色
package com.csdhsm.pattemdesign.visitor; /** * @Title: ShoppingCarVisitorImpl.java * @Description: Vistor实现类 * @author: Han * @date: 2016年7月2日 上午10:52:32 */ public class ShoppingCarVisitorImpl implements ShoppingCarVisitor { @Override public int visit(Book book) { int cost=0; //apply 5$ discount if book price is greater than 50 if(book.getPrice() > 50){ cost = book.getPrice()-5; }else cost = book.getPrice(); System.out.println("Book ISBN::"+book.getNumber() + " cost ="+cost); return cost; } @Override public int visit(Fruit fruit) { System.out.println(fruit.getName() + " price = " + fruit.getPrice()); return fruit.getPrice(); } }
客户端
package com.csdhsm.pattemdesign.visitor; public class Solution { public static void main(String[] args) { ItemElement[] items = new ItemElement[]{new Book(20, "1234"),new Book(100, "5678"), new Fruit("Banana", 10), new Fruit("Apple", 5)}; int total = calculatePrice(items); System.out.println("Total Cost = "+total); } private static int calculatePrice(ItemElement[] items) { ShoppingCarVisitor visitor = new ShoppingCarVisitorImpl(); int sum=0; for(ItemElement item : items){ sum = sum + item.accept(visitor); } return sum; } }
结果
OK,成功!
总结
访问者模式是一种行为设计模式。访问者模式被用在针对一组相同类型对象的操作。优点是,可以把针对此对象的操作逻辑转移到另外一个类上。
优点
好的扩展性
能够在不修改对象结构中的元素的情况下,为对象结构中的元素添加新的功能。
好的复用性
可以通过访问者来定义整个对象结构通用的功能,从而提高复用程度。
分离无关行为
可以通过访问者来分离无关的行为,把相关的行为封装在一起,构成一个访问者,这样每一个访问者的功能都比较单一。
缺点
对象结构变化很困难
不适用于对象结构中的类经常变化的情况,因为对象结构发生了改变,访问者的接口和访问者的实现都要发生相应的改变,代价太高。
破坏封装
访问者模式通常需要对象结构开放内部数据给访问者和ObjectStructrue,这破坏了对象的封装性。