【设计模式】访问者模式 购物车案例

  • 访问者模式是一种行为设计模式

     

  • 访问者模式被用在针对一组相同类型对象的操作

  • 优点是,可以把针对此对象的操作逻辑转移到另外一个类上

  • 适合场景:

    • 对象结构比较稳定,但经常需要在此对象结构上定义新的操作

    • 对一个对象结构中的对象进行很多不同的且不相关的操作,而需要避免这些操作“污染”这些对象的类,也不希望在增加新操作时修改这些类

UML图:

添加不同类型商品的购物车,当点击结算的时候,它计算出所有不同商品需付的费用

通过访问者模式把计算逻辑转移到了另外一个类(访问者)上面

商品接收访问者 accept(Visitor visitor),通过 visitor.visit(this) ,把商品本身传给访问者,访问者接收传递过来的商品,然后可以对该商品进行费用计算的逻辑,这样计算的逻辑就与商品本身解耦了。当计算逻辑发生变化后,不影响商品

商品接口类 Goods

package visitor.goods;

import visitor.visitor.Visitor;

/**
 * @author 土味儿
 * Date 2021/8/3
 * @version 1.0
 * 商品接口
 * 被访问者
 */
public interface Goods {
    /**
     * 接受访问者
     * 返回值为该商品的费用
     * 交给访问者去计算
     * @param visitor
     * @return
     */
    public int accept(Visitor visitor);

    public String getName();

    public int getNum();

    public int getPrice();
}

商品抽象类 AbstractGoods

package visitor.goods;

import visitor.visitor.Visitor;

/**
 * @author 土味儿
 * Date 2021/8/3
 * @version 1.0
 * 抽象商品类
 */
public abstract class AbstractGoods implements Goods{
    // 商品名称
    private String name;
    // 商品数量
    private int num;
    // 商品价格
    private int price;

    /**
     * 构造器
     * @param name
     * @param num
     */
    public AbstractGoods(String name, int num,int price) {
        this.name = name;
        this.num = num;
        this.price = price;
    }

    @Override
    public abstract int accept(Visitor visitor);

    public String getName() {
        return name;
    }

    public int getNum() {
        return num;
    }

    public int getPrice() {
        return price;
    }
}

具体商品

public class Book extends AbstractGoods{
    /**
     * 构造器
     *
     * @param name
     * @param num
     * @param price
     */
    public Book(String name, int num,int price) {
        super(name, num,price);
    }

    /**
     * 接受访问者,并且把自已(商品本身)传给访问者,把一些处理逻辑(计算费用)的  【操作权限】  给访问者
     * 当处理逻辑发生变化时(如:折扣率),在访问者中修改即可,不影响商品本身
     * 因为这个处理逻辑是在商品之外(即访问者中)进行的
     * @param visitor
     * @return
     */
    @Override
    public int accept(Visitor visitor) {
        return visitor.visit(this);
    }
}
public class Fruit extends AbstractGoods{
    /**
     * 构造器
     *
     * @param name
     * @param num
     * @param price
     */
    public Fruit(String name, int num, int price) {
        super(name, num, price);
    }

    /**
     * 接受访问者,并且把自已(商品本身)传给访问者,把一些处理逻辑(计算费用)的  【操作权限】  给访问者
     * 当处理逻辑发生变化时(如:折扣率),在访问者中修改即可,不影响商品本身
     * 因为这个处理逻辑是在商品之外(即访问者中)进行的
     * @param visitor
     * @return
     */
    @Override
    public int accept(Visitor visitor) {
        return visitor.visit(this);
    }
}

访问者接口 Visitor

每一个具体商品类目都对应一个visit方法。返回类型根据业务逻辑而定,此处是计算费用,用int

package visitor.visitor;

import visitor.goods.Book;
import visitor.goods.Fruit;

/**
 * @author 土味儿
 * Date 2021/8/3
 * @version 1.0
 * 访问者接口
 */
public interface Visitor {
    // 每一个具体商品类目都对应一个visit方法。返回类型根据业务逻辑而定,此处是计算费用,用int
    int visit(Book book);
    int visit(Fruit fruit);
}

具体访问者

public class ShoppingCarVisitorImpl implements Visitor {
    /**
     * 计算书的费用,并返回费用
     * 满100元减10元
     * @param book
     * @return
     */
    @Override
    public int visit(Book book) {
        int cost = book.getNum() * book.getPrice();
        // 满100元减10元
        if (cost >= 100) {
            cost = cost - 10;
        }
        return cost;
    }

    /**
     * 计算水果的费用,并返回费用
     * 满100元减15元
     * @param fruit
     * @return
     */
    @Override
    public int visit(Fruit fruit) {
        int cost = fruit.getNum() * fruit.getPrice();
        // 满100元减15元
        if (cost >= 100) {
            cost = cost - 15;
        }
        return cost;
    }
}

购物车 ShoppingCar

相当于结构对象(ObjectStructure)角色

package visitor;

import visitor.goods.Goods;
import visitor.visitor.*;

import java.util.ArrayList;
import java.util.List;

/**
 * @author 土味儿
 * Date 2021/8/3
 * @version 1.0
 * 购物车
 */
public class ShoppingCar {
    // 商品集合
    private static final List<Goods> goods = new ArrayList<>();
    // 访问者
    private static final Visitor visitor = new ShoppingCarVisitorImpl();

    // 添加商品
    public void add(Goods g) {
        goods.add(g);
    }

    // 删除商品
    public void remove(Goods g) {
        goods.remove(g);
    }

    // 计算总费用
    public int getCosts() {
        int sum = 0;
        int i = 1;
        for (Goods g : goods) {
            int c = g.accept(visitor);
            System.out.println("" + i++ + "\t[" + g.getName() + "] " + g.getNum() + "*" + g.getPrice() + "," + c +"元");
            sum = sum + c;
        }
        System.out.println("-----------------------\n合计:" + sum + " 元");
        return sum;
    }
}

测试客户端

package visitor;

import visitor.goods.Book;
import visitor.goods.Fruit;

/**
 * @author 土味儿
 * Date 2021/8/3
 * @version 1.0
 * 测试客户端
 */
public class Client {
    public static void main(String[] args) {
        // 创建购物车
        ShoppingCar shoppingCar = new ShoppingCar();
        // 添加商品
        shoppingCar.add(new Book("西游记",5,25));
        shoppingCar.add(new Book("三国演义",1,30));
        shoppingCar.add(new Fruit("苹果",2,5));
        shoppingCar.add(new Fruit("香蕉",5,8));
        shoppingCar.add(new Fruit("西瓜",50,3));

        // 计算总费用
        shoppingCar.getCosts();
    }
}

运行结果

1	[西游记] 5*25,115元
2	[三国演义] 1*30,30元
3	[苹果] 2*5,10元
4	[香蕉] 5*8,40元
5	[西瓜] 50*3,135元
-----------------------
合计:330 元
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

土味儿~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值