装饰模式详解-例子:电商计算应付金额

场景:电商项目中计算总支付金额,根据用户不同等级,使用优惠券情况,使用积分情况,使用余额情况,加上运费情况得出最后的应付金额。

版本1.0:

package decorator;

import java.util.Formatter;

public class First {
    /**
     * 办理会员不断赠送福利
     * @param args
     */
    public static void main(String[] args) {
        System.out.println("登录一个用户");
        User user = new User("0001", VipType.SECOND, "晓峰");
        double goodMoney = 195.5;
        System.out.println("您一共挑选了价值:" + goodMoney + "元的商品");
        System.out.println("您使用了一张满100减20的优惠券");
        Pay pay = new Pay(goodMoney);
        //使用一个 100 - 20 的卷
        CouponDesMoney couponDesMoney = new CouponDesMoney(100,20);
        PointDesMoney pointDesMoney = new PointDesMoney(200);
        VipDesMoney vipDesMoney = new VipDesMoney(user);

        couponDesMoney.setPay(pay);
        pay.setPayMoney(couponDesMoney.countMoney());

        pointDesMoney.setPay(pay);
        pay.setPayMoney(pointDesMoney.countMoney());

        vipDesMoney.setPay(pay);
        pay.setPayMoney(vipDesMoney.countMoney());

        System.out.println("您总共需要支付:" + pay.payMoney);
        /**
         * 登录一个用户
         * 您一共挑选了价值:195.5元的商品
         * 您使用了一张满100减20的优惠券
         * 您总共需要支付:157.0
         */
    }
}
//用户表
class User {
    private String userId;
    private VipType vipType;
    private String name;

    public User(String userId, VipType vipType, String name) {
        this.userId = userId;
        this.vipType = vipType;
        this.name = name;
    }

    public String getUserId() {
        return userId;
    }

    public void setUserId(String userId) {
        this.userId = userId;
    }

    public VipType getVipType() {
        return vipType;
    }

    public void setVipType(VipType vipType) {
        this.vipType = vipType;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
//会员类型
enum VipType {
    FIRST("普通会员"),SECOND("黄金会员"),THIRD("铂金会员");
    private String desc;
    VipType(String desc) {
        this.desc = desc;
    }
    public String getDesc() {
        return desc;
    }

}
//支付类
class Pay {
    double payMoney;
    public Pay(double payMoney) {
        this.payMoney = payMoney;
    }

    public double getPayMoney() {
        return payMoney;
    }

    public void setPayMoney(double payMoney) {
        this.payMoney = payMoney;
    }
}

abstract class DesMoney {
    Pay pay;
    void setPay(Pay pay) {
        this.pay = pay;
    }
    //减钱的操作
    abstract double countMoney();
}
//满减优惠券 满100 减 20
class CouponDesMoney extends DesMoney {
    double needMoney;
    double desMoney;

    public CouponDesMoney(double needMoney, double desMoney) {
        this.needMoney = needMoney;
        this.desMoney = desMoney;
    }
    @Override
    public double countMoney() {
        return Math.round(this.pay.payMoney >= needMoney ? (this.pay.payMoney - desMoney) : this.pay.payMoney);
    }
}
//积分优惠  100积分抵扣1元钱
class PointDesMoney extends DesMoney {
    double usePoint;

    public PointDesMoney(double usePoint) {
        this.usePoint = usePoint;
    }

    @Override
    public double countMoney() {
        return Math.round(this.pay.payMoney - (usePoint/100));
    }
}
//会员 总金额 进行打折
class VipDesMoney extends DesMoney {
    User user;

    public VipDesMoney(User user) {
        this.user = user;
    }

    //这里的会员打折可以在单独封装 类  一个会员类型 一个类  不多展开了  要不没完没了  搞不完了
    double countMoney() {
        double afterCountMoney = 0;
        switch (user.getVipType()) {
            case FIRST:
                afterCountMoney = this.pay.payMoney;
                break;
            case SECOND:
                afterCountMoney = this.pay.payMoney * 0.9;
                break;
            case THIRD:
                afterCountMoney = this.pay.payMoney * 0.8;
                break;
        }
        return Math.round(afterCountMoney);
    }
}

缺点:客户端需要针对每一个减钱操作都要传入一个当前金额。代码冗余,看着也不舒服,中间也容易被其他代码干扰

好处:我们现在如果增加一个减钱项,只需要增加一个减钱的类,然后再客户端进行修改下就可以了。

解决:可以将客户端中的减钱代码放到pay中 然后客户端只要设置一次pay 和相应需要做的减钱方式,但是这样就会导致 如果增加一个减钱项,就需要更改客户端代码 pay类  增加一个类。超过了两个修改点(增加和修改总数)。

总结下这个需求:

        1.动态的减钱项目

        2.顺序也是需要可控的,先执行哪项减钱项目,后执行哪项

装饰模式:动态的给一个类增加方法。

这里我们就是要动态的给pay方法增加减钱的功能。

package decorator.second;

public class Second {
    /**
     * 办理会员不断赠送福利
     * @param args
     */
    public static void main(String[] args) {
        System.out.println("登录一个用户");
        User user = new User("0001", VipType.SECOND, "晓峰");
        double goodMoney = 195.5;
        System.out.println("您一共挑选了价值:" + goodMoney + "元的商品");
        Pay pay = new Pay();
        //这里开始为pay 进行添加 减支付金额的功能  也可以做加法  比如增加 运费
        //优惠券装饰
        CouponPayDecorator cpd = new CouponPayDecorator(pay);
        cpd.setCoupon(100, 20);
        //积分装饰
        PointPayDecorator ppd = new PointPayDecorator(cpd);
        ppd.setPoint(100);
        //会员打折
        VipPayDecorator vpd = new VipPayDecorator(ppd);
        vpd.setUser(user);

        double needPay = vpd.count(goodMoney);
        System.out.println("您总共需要支付:" + needPay);
        /**
         * 登录一个用户
         * 您一共挑选了价值:195.5元的商品
         * 优惠券减免:原价195.5,现价:175.5
         * 积分减免:原价175.5,现价:174.5
         * 会员打折:原价174.5,现价:157.05
         * 您总共需要支付:157.05
         */
    }
}

//用户表
class User {
    private String userId;
    private VipType vipType;
    private String name;

    public User(String userId, VipType vipType, String name) {
        this.userId = userId;
        this.vipType = vipType;
        this.name = name;
    }

    public String getUserId() {
        return userId;
    }

    public void setUserId(String userId) {
        this.userId = userId;
    }

    public VipType getVipType() {
        return vipType;
    }

    public void setVipType(VipType vipType) {
        this.vipType = vipType;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

//会员类型
enum VipType {
    FIRST("普通会员"),SECOND("黄金会员"),THIRD("铂金会员");
    private String desc;
    VipType(String desc) {
        this.desc = desc;
    }
    public String getDesc() {
        return desc;
    }

}

//支付类
class Pay {
    public double count(double money) {
        return money;
    };
}
class PayDecorator extends Pay{
    public Pay pay;

    public PayDecorator(Pay pay) {
        this.pay = pay;
    }

    public double count(double money) {
        return super.count(money);
    }
}
//满减优惠券 满100 减 20
class CouponPayDecorator extends PayDecorator {
    double needMoney;
    double desMoney;
    public  CouponPayDecorator(Pay pay) {
        super(pay);
    }
    public void setCoupon(double needMoney, double desMoney) {
        this.needMoney = needMoney;
        this.desMoney = desMoney;
    }
    public double count(double money) {
        double beforeMoney = this.pay.count(money);
        double afterMoney = beforeMoney >= needMoney ? (beforeMoney - desMoney) : beforeMoney;
        System.out.println("优惠券减免:原价" + beforeMoney + ",现价:" + afterMoney);
        return afterMoney;

    }
}

//积分优惠  100积分抵扣1元钱
class PointPayDecorator extends PayDecorator {
    int usePoint;
    public PointPayDecorator(Pay pay) {
        super(pay);
    }
    public void setPoint(int usePoint) {
        this.usePoint = usePoint;
    }

    @Override
    public double count(double money) {
        double beforeMoney = this.pay.count(money);
        double afterMoney = beforeMoney - (usePoint/100);
        System.out.println("积分减免:原价" + beforeMoney + ",现价:" + afterMoney);
        return afterMoney;
    }
}

//会员 总金额 进行打折
class VipPayDecorator extends PayDecorator {
    User user;
    public VipPayDecorator(Pay pay) {
        super(pay);
    }
    public void setUser(User user) {
        this.user = user;
    }

    //这里的会员打折可以在单独封装 类  一个会员类型 一个类  不多展开了  要不没完没了  搞不完了
    public double count(double money) {
        double beforeMoney = this.pay.count(money);
        double afterMoney = 0;
        switch (user.getVipType()) {
            case FIRST:
                afterMoney = beforeMoney;
                break;
            case SECOND:
                afterMoney = beforeMoney * 0.9;
                break;
            case THIRD:
                afterMoney = beforeMoney * 0.8;
                break;
        }
        System.out.println("会员打折:原价" + beforeMoney + ",现价:" + afterMoney);
        return afterMoney;
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值