定义
动态的向一个现有的对象添加新的功能,同时又不改变其结构。它属于结构型模式。
优点
装饰类和被装饰类可以独立发展,不会相互耦合,装饰模式是继承的一个替代模式,装饰模式可以动态扩展一个实现类的功能。
缺点
多层装饰比较复杂。
需求
在订单提交的时候,订单价格和结算价格其实是两码事,订单价格是当前商品成交价格,而结算价格是用户最终需要支付的金额,最终支付的金额并不是一成不变,它也并不是商品成交价格,能改变结算价格的因素很多,比如满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;
}
}
在添加订单时的使用,用户使用金币与优惠券叠加使用