设计模式之装饰者模式

定义

动态的向一个现有的对象添加新的功能,同时又不改变其结构。它属于结构型模式。

优点

装饰类和被装饰类可以独立发展,不会相互耦合,装饰模式是继承的一个替代模式,装饰模式可以动态扩展一个实现类的功能。

缺点

多层装饰比较复杂。

需求

在订单提交的时候,订单价格和结算价格其实是两码事,订单价格是当前商品成交价格,而结算价格是用户最终需要支付的金额,最终支付的金额并不是一成不变,它也并不是商品成交价格,能改变结算价格的因素很多,比如满100减10元,VIP用户再减5块。

装饰者模式价格运算实现

思路分析

1、创建接口(MoneyOperation),定义订单价格计算,因为所有价格波动,都是基于订单价格来波动的。
2、创建订单价格计算类(OrderPayMoneyOperation),实现MoneyOperation接口,实现订单价格计算。
3、创建装饰者对象(Decorator),以供功能扩展。
4、实现优惠券优惠金额计算功能扩展,创建Decorator的扩展类CouponsMoneyOperation,先计算订单金额,再计算优惠 券使用之后的优惠金额。
5、实现金币抵现功能扩展,创建Decorator的扩展类GoldMoneyOperation,先计算订单金额,再实现金币优惠之后的金额

实现

基础接口:创建接口 MoneySum ,该接口只用于定义计算订单金额的方法。

public interface MoneyOperation {

    /***
     * 订单金额计算
     * @return
     */
    Integer operation(Order order);
}

订单金额计算类:创建类 OrderPayMoneyOperation 实现订单金额的计算。(基础运算)

@Component
public class OrderPayMoneyOperation implements MoneyOperation {

    @Autowired
    private ItemDao itemDao;

    /***
     * 订单金额计算
     */
    @Override
    public Integer operation(Order order) {
        //根据ID查询商品
        Item item = itemDao.findById(order.getItemId());
        //计算订单金额
        return item.getPrice()*order.getNum();
    }
}

装饰者类:创建装饰者类 DecoratorMoneySum 供其他类扩展。

public abstract class Decorator implements MoneyOperation {

    private MoneyOperation moneyOperation;

    public void setMoneyOperation(MoneyOperation moneyOperation) {
        this.moneyOperation = moneyOperation;
    }

    /***
     * 订单金额计算
     */
    @Override
    public Integer operation(Order order) {
        return moneyOperation.operation(order);
    }
}

金币抵扣计算:创建类 GoldMoneyOperation 扩展装饰者类,实现抵扣价格计算。

@Component
public class  GoldMoneyOperation Decorator{

    @Autowired
    private ThreadUserLog threadUserLog;

    @Autowired
    private UserDao userDao;

    /***
     * 扩展功能:金币优惠后计算
     */
    @Override
    public Integer operation(Order order) {
        //订单基本金额计算
        Integer payMoney = super.operation(order);

        //金币优惠
        payMoney = gold(payMoney);
        return payMoney;
    }

    /***
     * 金币优惠计算
     */
    public Integer gold(Integer payMoney) {
        if(payMoney<=0){
            return 0;
        }
        //获取当前用户的会话->结合了享元模式
        LogComponent logComponent = threadUserLog.get();
        User user = userDao.findByUserName(logComponent.getUsername());
        if(user.getGold()<=0){
            return payMoney;
        }

        //剩余金币
        int remaining = 0;

        //金币比payMoney小
        if(payMoney>=user.getGold()){
            payMoney = payMoney-user.getGold();
        }else{
            remaining = user.getGold()-payMoney;
            payMoney = 0;
        }
        //更新用户剩余金币
        userDao.modifyGold(logComponent.getUsername(),remaining);
        return payMoney;
    }
}

优惠券计算:创建类 CouponsMoneyOperation扩展装饰者类,实现优惠价格计算。

@Component
public class CouponsMoneyOperation extends Decorator {

    @Autowired
    private ThreadUserLog threadUserLog;

    @Autowired
    private CouponsDao couponsDao;

    /***
     * 功能扩展,增加优惠券折扣计算
     */
    @Override
    public Integer operation(Order order) {
        //订单金额计算
        Integer payMoney = super.operation(order);
        //优惠券金额优惠后金额计算
        payMoney = couponsMoney(payMoney,order.getCouponsId());
        return payMoney>0? payMoney:0;
    }


    /***
     * 优惠券折扣计算
     */
    public Integer couponsMoney(Integer payMoney,String couponsId) {
        if(payMoney<=0){
            return 0;
        }

        //获取用户username->结合了享元模式
        LogComponent logComponent = threadUserLog.get();
        //查询优惠券
        Coupons coupons = couponsDao.findByIdAndUserName(couponsId,logComponent.getUsername());
        if(coupons==null){
            return payMoney;
        }

        //价格计算
        payMoney = payMoney-coupons.getMoney();
        //标记优惠券
        couponsDao.modifyCouponsStatus(couponsId);
        return payMoney>0? payMoney:0;
    }
}

在添加订单时的使用,用户使用金币与优惠券叠加使用
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值