场景:电商项目中计算总支付金额,根据用户不同等级,使用优惠券情况,使用积分情况,使用余额情况,加上运费情况得出最后的应付金额。
版本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;
}
}