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

来源:互联网 发布:数据库原理精品课程 编辑:程序博客网 时间:2024/06/03 11:17

概念:

访问者模式(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、如果类不允许修改现代码怎么办?面对这些问题,最好的解决方法就是使用访问者模式,访问者模式适用于数据结构相对稳定的系统,把数据结构和算法解耦。这样修改功能不会影响到数据本身。


上面的例子,新增商品数据也非常方便。增加一个商品类和它的购物访问类就可以了。
0 0
原创粉丝点击