设计模式的应用场景(19)--访问者模式
访问者模式
定义:封装一些施加于某种数据结构上的操作,一旦这些操作需要改变的话,接受这个操作的数据结构可以保持不变。
优点:使用访问者模式,对于原来的类层次增加新的操作只需要实现一个具体访问者角色,而不必改变整个类层次。每个具体的访问者角色都对应于一个相关操作。
缺点:不适合具体元素角色经常发生变化的情况。每增加一个元素类都需要修改访问者类(也包括访问者类的子类或者实现类),修改起来相当麻烦。也就是说,在元素类数目不确定的情况下,应该慎用访问者模式。
使用场合:当一个对象结构包括很多类对象,它们有不同的接口,而系统要求这些对象实施一些依赖于某具体类的操作时,就可以使用访问者模式。
小巩要设计超市收银系统,碰到了困难,有的按重量计价,有的按物件计价,还有其他计价方式。
这时候可以使用访问者模式。
首先设计抽象元素类,提供访问者需要的accept方法
public interface Goods {
double accept(Visitor visitor);
}
具体元素类,包括猪肉类,,酒类,电视机类
public class Pig implements Goods {
public double accountByUnit() {
System.out.println("猪肉按斤计价,购买的数量为:" + getCount() + "斤,购买的单价为:" + getPrice() + ",总价为:" + getCount() * getPrice());
return getCount() * getPrice();
}
public double accept(Visitor visitor) {
return visitor.visit(this);
}
public float getCount(){ return count; }
public void setCount(float count){ this.count = count; }
public float getPrice(){ return price; }
public void setPrice(float price){ this.price = price; }
private float count;
private float price;
}
public class Wine implements Goods {
public double accountByBottle() {
System.out.println("酒按瓶计价,购买的数量为:" + getCount() + "瓶,购买的单价为:" + getPrice() + ",总价为:" + getCount() * getPrice());
return getCount() * getPrice();
}
public double accept(Visitor visitor) {
return visitor.visit(this);
}
public int getCount(){
return count;
}
public void setCount(int count){
this.count = count;
}
public float getPrice(){ return price; }
public void setPrice(float price){ this.price = price; }
private int count;
private float price;
}
public class Television implements Goods {
public double accountByPiece() {
System.out.println("电视按台计价,购买的数量为:" + getCount() + "台,购买的单价为:" + getPrice() + ",总价为:" + getCount() * getPrice());
return getCount() * getPrice();
}
public double accept(Visitor visitor) {
return visitor.visit(this);
}
public int getCount(){
return count;
}
public void setCount(int count){
this.count = count;
}
public float getPrice(){ return price; }
public void setPrice(float price){ this.price = price; }
private int count;
private float price;
}
需要一个购物车类收集要买的具体对象
import java.util.List;
import java.util.ArrayList;
public class ShoppingCart {
public void add(Object object) {
list.add(object);
}
public void remove(Object object) {
list.remove(object);
}
public List getList() {
return list;
}
private List list = new ArrayList();
}
下面是访问者接口和实现类
public interface Visitor {
double visit(Wine wine);
double visit(Pig pig);
double visit(Television television);
}
public class VisitorImpl implements Visitor {
public double visit(Wine wine) {
return wine.accountByBottle();
}
public double visit(Pig pig) {
return pig.accountByUnit();
}
public double visit(Television television) {
return television.accountByPiece();
}
}
设计收银机类可以调用具体物件供访问的收费方法
public class AccountMachine {
private double amt;
public void account(List list) {
Visitor visitor = new VisitorImpl();
for (int i = 0; i < list.size(); i++) {
amt += ((Goods)list.get(i)).accept(visitor);
}
}
public double getAmt() {
return amt;
}
}
客户端调用的代码
public class Client {
public static void main(String[] argv) {
Wine wine = new Wine();
wine.setCount(10);
wine.setPrice(20f);
Pig pig = new Pig();
pig.setCount(10f);
pig.setPrice(15f);
Television television = new Television();
television.setCount(1);
television.setPrice(2000f);
ShoppingCart shoppingCart = new ShoppingCart();
shoppingCart.add(wine);
shoppingCart.add(pig);
shoppingCart.add(television);
AccountMachine accountMachine = new AccountMachine();
accountMachine.account(shoppingCart.getList());
System.out.println("本次购物车内所有物品的总价为:" + accountMachine.getAmt());
}
}