【設計模式】- 裝飾器模式

裝飾器模式能夠實現爲對象動態添加裝修功能,它能從一個對象的外部來給對象添加功能,所以有非常靈活的擴展性,我們可以在對原來的代碼毫無修改的前提下,爲對象添加新功能

除此之外,裝飾器模式還能夠實現對象的動態組合,藉此我們可以很靈活地給動態組合的對象,匹配所需要的功能。

什麼是裝飾器模式?

裝飾器模式包括了以下幾個角色:接口、具體對象、裝飾類、具體裝飾類
接口定義了具體對象的一些實現方法;具體對象定義了一些初始化操作;
裝飾類則是一個抽象類,主要用來初始化具體對象的一個類;其他的具體裝飾類都繼承了該抽象類。

一個簡單的Demo

  1. 基礎裝飾接口:
/**
 * 基礎裝飾接口.
 */
public interface IDecorator {

    /**
     * 裝修方法.
     */
    void decorate();
}
  1. 裝飾基礎類
/**
 * 裝飾基礎類.
 *
 */
public class Decorator implements IDecorator {

    @Override
    public void decorate() {
        System.out.println("水電鋪設、牆面粉刷。。。");
    }
}
  1. 抽象類
/**
 * 抽象類.
 *
 */
public abstract class BaseDecorator implements IDecorator {

    private IDecorator decorator;

    public BaseDecorator(IDecorator decorator) {
        this.decorator = decorator;
    }

    @Override
    public void decorate() {
        if (decorator != null) {
            decorator.decorate();
        }
    }
}
  1. 具體裝飾類
/**
 * 窗簾裝飾類.
 *
 */
public class CurtainDecorator extends BaseDecorator {

    public CurtainDecorator(IDecorator decorator) {
        super(decorator);
    }

    @Override
    public void decorate() {
        System.out.println("窗簾裝飾。。。");
        super.decorate();
    }
}
  1. 測試
    public static void main(String[] args) {
        Decorator decorator = new Decorator();

        CurtainDecorator curtainDecorator = new CurtainDecorator(decorator);
        curtainDecorator.decorate();
    }

執行結果:

窗簾裝飾。。。
水電鋪設、牆面粉刷。。。

優化電商系統中的商品價格策略

由於篇幅原因,只展示部分核心代碼。

  1. 計算支付金額接口類
/**
 * 計算支付金額接口類.
 *
 * @author liusj
 * @date 2021/8/23
 */
public interface IBaseCount {

    /**
     * 商品支付金額.
     *
     * @param orderDetail
     * @return
     */
    BigDecimal countPayMoney(OrderDetail orderDetail);
}
  1. 支付基礎實現類
/**
 * 支付基礎實現類.
 *
 * @author liusj
 * @date 2021/8/23
 */
public class BaseCount implements IBaseCount {

    @Override
    public BigDecimal  countPayMoney(OrderDetail orderDetail) {
        orderDetail.setPayMoney(orderDetail.getMerchandise().getPrice());
        System.out.println("商品元單價金額爲:" + orderDetail.getPayMoney());
        return orderDetail.getPayMoney();
    }
}
  1. 計算支付金額的抽象類(裝飾類)
/**
 * 計算支付金額的抽象類.
 *
 * @author liusj
 * @date 2021/8/23
 */
@Data
public abstract class BaseCountDecorator implements IBaseCount {

    private IBaseCount count;

    public BaseCountDecorator(IBaseCount count) {
        this.count = count;
    }

    @Override
    public BigDecimal countPayMoney(OrderDetail orderDetail) {
        BigDecimal payTotalMoney = new BigDecimal(0);
        if (count != null) {
            payTotalMoney = count.countPayMoney(orderDetail);
        }
        return payTotalMoney;
    }
}
  1. 計算使用優惠券後的金額 (具體裝飾類)
/**
 * 計算使用優惠券後的金額.
 *
 * @author liusj
 * @date 2021/8/23
 */
public class CouponDecorator extends BaseCountDecorator {

    public CouponDecorator(IBaseCount count) {
        super(count);
    }

    @Override
    public BigDecimal countPayMoney(OrderDetail orderDetail) {
        BigDecimal payTotalMoney = new BigDecimal(0);
        super.countPayMoney(orderDetail);
        payTotalMoney = countCouponPayMoney(orderDetail);
        return payTotalMoney;
    }

    private BigDecimal countCouponPayMoney(OrderDetail orderDetail) {
        BigDecimal coupon = orderDetail.getMerchandise()
                .getSupportPromotions()
                .get(PromotionType.COUPON)
                .getUserCoupon()
                .getCoupon();
        System.out.println("優惠金額:" + coupon);

        orderDetail.setPayMoney(orderDetail.getPayMoney().subtract(coupon));

        return orderDetail.getPayMoney();
    }
}
  1. 計算使用紅包後的金額
/**
 * 計算使用紅包後的金額.
 *
 * @author liusj
 * @date 2021/8/23
 */
public class RedPacketDecorator extends BaseCountDecorator {

    public RedPacketDecorator(IBaseCount count) {
        super(count);
    }

    @Override
    public BigDecimal countPayMoney(OrderDetail orderDetail) {
        BigDecimal payTotalMoney = new BigDecimal(0);
        super.countPayMoney(orderDetail);
        payTotalMoney = countReadPacketMoney(orderDetail);
        return payTotalMoney;
    }

    private BigDecimal countReadPacketMoney(OrderDetail orderDetail) {
        BigDecimal redPacket = orderDetail.getMerchandise()
                .getSupportPromotions()
                .get(PromotionType.READ_PACKED)
                .getUserRedPacket()
                .getRedPacket();
        System.out.println("紅包優惠金額:" + redPacket);

        orderDetail.setPayMoney(orderDetail.getPayMoney().subtract(redPacket));

        return orderDetail.getPayMoney();
    }
}
  1. 計算促銷後的支付價格 (對象的動態組合)
/**
 * 計算促銷後的支付價格.
 *
 * @author liusj
 * @date 2021/8/23
 */
public class PromotionFactory {

    public static BigDecimal getPayMoney(OrderDetail orderDetail) {
        // 獲取商品設定的促銷類型
        Map<PromotionType, SupportPromotions> supportPromotions = orderDetail.getMerchandise().getSupportPromotions();

        // 初始化計算類
        IBaseCount baseCount = new BaseCount();
        // 遍歷設置的促銷類型,通過裝飾器組合促銷類型
        if (supportPromotions != null && supportPromotions.size() > 0) {
            for (PromotionType promotionType : supportPromotions.keySet()) {
                baseCount = promotion(supportPromotions.get(promotionType), baseCount);
            }
        }
        return baseCount.countPayMoney(orderDetail);
    }

    /**
     * 組合促銷類型.
     *
     * @param supportPromotions
     * @param baseCount
     * @return
     */
    private static IBaseCount promotion(SupportPromotions supportPromotions, IBaseCount baseCount) {
        if (supportPromotions.getPromotionType() == PromotionType.COUPON) {
            baseCount = new CouponDecorator(baseCount);
        } else if (supportPromotions.getPromotionType() == PromotionType.READ_PACKED) {
            baseCount = new RedPacketDecorator(baseCount);
        }
        return baseCount;
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章