您的位置:首页 > 编程语言 > Java开发

Java设计模式之--访问者模式(Visitor)

2016-06-24 12:12 811 查看
概念:

访问者模式(Visitor)行为设计模式。访问者模式被用在针对一组相同类型对象的操作。优点是,可以把针对此对象的操作逻辑转移到另外一个类上。用于数据结构和作用于结构上的操作解耦合,使得操作集合可相对自由地演化。访问者模式适用于数据结构相对稳定算法又易变化的系统。因为访问者模式使得算法操作增加变得容易。若系统数据结构对象易于变化,经常有新的数据对象增加进来,则不适合使用访问者模式。访问者模式的优点是增加操作很容易,因为增加操作意味着增加新的访问者。访问者模式将有关行为集中到一个访问者对象中,其改变不影响系统数据结构。其缺点就是增加新的数据结构很困难。

案例:

本文将展示如何利用访问者模式去实现电商购物车系统,平台上的商品的销售活动(操作行为)可能经常改变,但商品本身基本数据却相对稳定,这里就可以应用访问者模式,将行为与数据分离开来,达到解耦的目的。下面的例子并对访问者模式进行改进,让增加数据与改变操作行为一样方便。

先来看类图:



先定义商品项接口:两个方法等实现 

public interface GoodsItem {
public double accept(ShoppingCartVisitor visitor);

public ShoppingCartVisitor getSelfVisitor();
}


定义购物接口:

public interface ShoppingCartVisitor {
public double visitor(GoodsItem goodsItem);
}


定义商品类,实现GoodsItem 接口:

奶粉类:

public class Milk implements GoodsItem {

private String brand;
private double price;
private int number;

public int getNumber() {
return number;
}

public Milk(String brand, double price, int number) {
this.brand = brand;
this.price = price;
this.number = number;
}

public String getBrand() {
return brand;
}

public double getPrice() {
return price;
}

@Override
public double accept(ShoppingCartVisitor visitor) {
return visitor.visitor(this);
}

@Override
public ShoppingCartVisitor getSelfVisitor() {
return new MilkVisitor();
}
}


樱桃:

public class Cherry implements GoodsItem {

private double price;

private int weight;

public double getPrice() {
return price;
}

public int getWeight() {
return weight;
}

public Cherry(double price, int weight) {
this.price = price;
this.weight = weight;
}

@Override
public double accept(ShoppingCartVisitor visitor) {
return visitor.visitor(this);
}

@Override
public ShoppingCartVisitor getSelfVisitor() {
return new CherryVisitor();
}
}


增加奶粉Visitor

public class MilkVisitor implements  ShoppingCartVisitor {
@Override
public double visitor(GoodsItem goodsItem) {
Milk milk = (Milk)goodsItem;
double cost = milk.getPrice()*milk.getNumber();
System.out.println(String.format("%s 单盒价:%s,盒数%s 总价:%s",milk.getBrand(),milk.getPrice(),milk.getNumber(),cost));
//奶粉满300减50
if(cost>=300){
cost-=50;
}
System.out.println(String.format("%s 今日满300减50,优惠后总价:%s",milk.getBrand(),cost));
return cost;
}
}


增加樱桃Visitor

public class CherryVisitor implements  ShoppingCartVisitor {
@Override
public double visitor(GoodsItem goodsItem) {
Cherry cherry = (Cherry)goodsItem;
double cost = cherry.getPrice()*cherry.getWeight();
System.out.println(String.format("Cherry 单价:%s 重量:%s 总价:%s",cherry.getPrice(),cherry.getWeight(),cost));
//进口樱桃 8折
cost*=0.8;
System.out.println(String.format("Cherry 今日8折,折后总价%s",cost));
return cost;
}
}


最后购物平台类:

public class ShopingClient {
private List<GoodsItem> list;

public ShopingClient(List<GoodsItem> list) {
this.list = list;
}

public List<GoodsItem> getList() {
return list;
}

public void setList(List<GoodsItem> list) {
this.list = list;
}

public double perchase() {
double costTotal = 0.0;
for (GoodsItem goodsItem : list) {
costTotal += goodsItem.accept(goodsItem.getSelfVisitor());
}
System.out.println(String.format("购物总价%s", costTotal));
return costTotal;
}

}


写代码测试:

public class WorkClass {
public void test() {
List<GoodsItem> list = new ArrayList<GoodsItem>();
list.add(new Milk("某品牌奶粉",160.0,2));
list.add(new Cherry(80.0,5));
ShopingClient shopingClient = new ShopingClient(list);
double totalcost=shopingClient.perchase();

}
}


测试结果输出:

I/System.out: 某品牌奶粉 单盒价:160.0,盒数2 总价:320.0

I/System.out: 某品牌奶粉 今日满300减50,优惠后总价:270.0

I/System.out: Cherry 单价:80.0 重量:5 总价:400.0

I/System.out: Cherry 今日8折,折后总价320.0

I/System.out: 购物总价590.0

结语:

上面的例子,新增商品数据也非常方便。增加一个商品类和它的购物访问类就可以了。不用改到已有的类和接口。


如果项目需要为一个现有的类增加新功能,会考虑以下几个事情:1、新功能会不会与现有功能出现兼容性问题?2、以后会不会再需要添加?3、如果类不允许修改现代码怎么办?面对这些问题,最好的解决方法就是使用访问者模式,访问者模式适用于数据结构相对稳定的系统,把数据结构和算法解耦。这样修改功能不会影响到数据本身。

上面的例子,新增商品数据也非常方便。增加一个商品类和它的购物访问类就可以了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息