小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

重學(xué) Java 設(shè)計模式:實戰(zhàn)策略模式「模擬多種營銷類型優(yōu)惠券,折扣金額計算策略場景」

 小傅哥 2021-12-13


作者:小傅哥
博客:https:// - 原創(chuàng)系列專題文章

沉淀、分享、成長,讓自己和他人都能有所收獲!😄

一、前言

文無第一,武無第二

不同方向但同樣努力的人,都有自身的價值和亮點,也都是可以互相學(xué)習(xí)的。不要太過于用自己手里的矛去攻擊別人的盾🛡,哪怕一時爭辯過了也多半可能是你被安放的角色不同。取別人之強(qiáng)補(bǔ)自己之弱,矛與盾的結(jié)合可能就是坦克。

能把復(fù)雜的知識講的簡單很重要

在學(xué)習(xí)的過程中我們看過很多資料、視頻、文檔等,因為現(xiàn)在資料視頻都較多所以往往一個知識點會有多種多樣的視頻形式講解。除了推廣營銷以外,確實有很多人的視頻講解非常優(yōu)秀,例如李永樂老師的短視頻課,可以在一個黑板上把那么復(fù)雜的知識,講解的那么容易理解,那么透徹。而我們學(xué)習(xí)編程的人也是,不只是要學(xué)會把知識點講明白,也要寫明白。

🙉提升自己的眼界交往更多同好

有時候圈子很重要,就像上學(xué)期間大家都會發(fā)現(xiàn)班里有這樣一類學(xué)生👩?🎓不怎么聽課,但是就是學(xué)習(xí)好。那假如讓他回家呆著,不能在課堂里呢?類似的圈子還有;圖書館、網(wǎng)吧、車友群、技術(shù)群等等,都可以給你帶來同類愛好的人所分享出來的技能或者大家一起烘托出的氛圍幫你成長。

二、開發(fā)環(huán)境

  1. JDK 1.8
  2. Idea + Maven
  3. 涉及工程三個,可以通過關(guān)注公眾號bugstack蟲洞棧,回復(fù)源碼下載獲取(打開獲取的鏈接,找到序號18)
工程描述
itstack-demo-design-20-01使用一坨代碼實現(xiàn)業(yè)務(wù)需求
itstack-demo-design-20-02通過設(shè)計模式優(yōu)化改造代碼,產(chǎn)生對比性從而學(xué)習(xí)

三、策略模式介紹

策略模式,圖片來自 refactoringguru.cn

策略模式是一種行為模式,也是替代大量ifelse的利器。它所能幫你解決的是場景,一般是具有同類可替代的行為邏輯算法場景。比如;不同類型的交易方式(信用卡、支付寶、微信)、生成唯一ID策略(UUID、DB自增、DB+Redis、雪花算法、Leaf算法)等,都可以使用策略模式進(jìn)行行為包裝,供給外部使用。

諸葛亮錦囊妙計

策略模式也有點像三國演義中諸葛亮給劉關(guān)張的錦囊;

  • 第一個錦囊:見喬國老,并把劉備娶親的事情du搞得東吳人盡皆知。
  • 第二個錦囊:用謊言(曹操打荊州)騙泡在溫柔鄉(xiāng)里的劉備回去。
  • 第三個錦囊:讓孫夫人擺平東吳的追兵,她是孫權(quán)妹妹,東吳將領(lǐng)懼她三分。

四、案例場景模擬

場景模擬;商品支付使用營銷優(yōu)惠券

在本案例中我們模擬在購買商品時候使用的各種類型優(yōu)惠券(滿減、直減、折扣、n元購)

這個場景幾乎也是大家的一個日常購物省錢渠道,購買商品的時候都希望找一些優(yōu)惠券,讓購買的商品更加實惠。而且到了大促的時候就會有更多的優(yōu)惠券需要計算那些商品一起購買更加優(yōu)惠!!!

這樣的場景有時候用戶用起來還是蠻爽的,但是最初這樣功能的設(shè)定以及產(chǎn)品的不斷迭代,對于程序員👨?💻?開發(fā)還是不太容易的。因為這里包括了很多的規(guī)則和優(yōu)惠邏輯,所以我們模擬其中的一個計算優(yōu)惠的方式,使用策略模式來實現(xiàn)。

五、用一坨坨代碼實現(xiàn)

這里我們先使用最粗暴的方式來實現(xiàn)功能

對于優(yōu)惠券的設(shè)計最初可能非常簡單,就是一個金額的抵扣,也沒有現(xiàn)在這么多種類型。所以如果沒有這樣場景的經(jīng)驗話,往往設(shè)計上也是非常簡單的。但隨著產(chǎn)品功能的不斷迭代,如果程序最初設(shè)計的不具備很好的擴(kuò)展性,那么往后就會越來越混亂。

1. 工程結(jié)構(gòu)

itstack-demo-design-20-01
└── src
    └── main
        └── java
            └── org.itstack.demo.design
                └── CouponDiscountService.java
  • 一坨坨工程的結(jié)構(gòu)很簡單,也是最直接的面向過程開發(fā)方式。

2. 代碼實現(xiàn)

/**
 * 博客:https:// - 沉淀、分享、成長,讓自己和他人都能有所收獲!
 * 公眾號:bugstack蟲洞棧
 * Create by 小傅哥(fustack) @2020
 * 優(yōu)惠券折扣計算接口
 * <p>
 * 優(yōu)惠券類型;
 * 1. 直減券
 * 2. 滿減券
 * 3. 折扣券
 * 4. n元購
 */
public class CouponDiscountService {

    public double discountAmount(int type, double typeContent, double skuPrice, double typeExt) {
        // 1. 直減券
        if (1 == type) {
            return skuPrice - typeContent;
        }
        // 2. 滿減券
        if (2 == type) {
            if (skuPrice < typeExt) return skuPrice;
            return skuPrice - typeContent;
        }
        // 3. 折扣券
        if (3 == type) {
            return skuPrice * typeContent;
        }
        // 4. n元購
        if (4 == type) {
            return typeContent;
        }
        return 0D;
    }

}
  • 以上是不同類型的優(yōu)惠券計算折扣后的實際金額。
  • 入?yún)?#xff1b;優(yōu)惠券類型、優(yōu)惠券金額、商品金額,因為有些優(yōu)惠券是滿多少減少多少,所以增加了typeExt類型。這也是方法的不好擴(kuò)展性問題。
  • 最后是整個的方法體中對優(yōu)惠券抵扣金額的實現(xiàn),最開始可能是一個最簡單的優(yōu)惠券,后面隨著產(chǎn)品功能的增加,不斷的擴(kuò)展if語句。實際的代碼可能要比這個多很多。

六、策略模式重構(gòu)代碼

接下來使用策略模式來進(jìn)行代碼優(yōu)化,也算是一次很小的重構(gòu)。

與上面面向流程式的開發(fā)這里會使用設(shè)計模式,優(yōu)惠代碼結(jié)構(gòu),增強(qiáng)整體的擴(kuò)展性。

1. 工程結(jié)構(gòu)

itstack-demo-design-20-02
└── src
    └── main
        └── java
            └── org.itstack.demo.design
                ├── event
                │    └── MJCouponDiscount.java
                │    └── NYGCouponDiscount.java
                │    └── ZJCouponDiscount.java
                │    └── ZKCouponDiscount.java
                ├── Context.java
                └── ICouponDiscount.java

策略模式模型結(jié)構(gòu)

策略模式模型結(jié)構(gòu)

  • 整體的結(jié)構(gòu)模式并不復(fù)雜,主要體現(xiàn)的不同類型的優(yōu)惠券在計算優(yōu)惠券方式的不同計算策略。
  • 這里包括一個借口類(ICouponDiscount)以及四種優(yōu)惠券類型的實現(xiàn)方式。
  • 最后提供了策略模式的上下文控制類處理,整體的策略服務(wù)。

2. 代碼實現(xiàn)

2.1 優(yōu)惠券接口

public interface ICouponDiscount<T> {

    /**
     * 優(yōu)惠券金額計算
     * @param couponInfo 券折扣信息;直減、滿減、折扣、N元購
     * @param skuPrice   sku金額
     * @return           優(yōu)惠后金額
     */
    BigDecimal discountAmount(T couponInfo, BigDecimal skuPrice);

}

  • 定義了優(yōu)惠券折扣接口,也增加了泛型用于不同類型的接口可以傳遞不同的類型參數(shù)。
  • 接口中包括商品金額以及出參返回最終折扣后的金額,這里在實際開發(fā)中會比現(xiàn)在的接口參數(shù)多一些,但核心邏輯是這些。

2.2 優(yōu)惠券接口實現(xiàn)

滿減

public class MJCouponDiscount implements ICouponDiscount<Map<String,String>>  {

    /**
     * 滿減計算
     * 1. 判斷滿足x元后-n元,否則不減
     * 2. 最低支付金額1元
     */
    public BigDecimal discountAmount(Map<String,String> couponInfo, BigDecimal skuPrice) {
        String x = couponInfo.get("x");
        String o = couponInfo.get("n");

        // 小于商品金額條件的,直接返回商品原價
        if (skuPrice.compareTo(new BigDecimal(x)) < 0) return skuPrice;
        // 減去優(yōu)惠金額判斷
        BigDecimal discountAmount = skuPrice.subtract(new BigDecimal(o));
        if (discountAmount.compareTo(BigDecimal.ZERO) < 1) return BigDecimal.ONE;

        return discountAmount;
    }
}

直減

public class ZJCouponDiscount implements ICouponDiscount<Double>  {

    /**
     * 直減計算
     * 1. 使用商品價格減去優(yōu)惠價格
     * 2. 最低支付金額1元
     */
    public BigDecimal discountAmount(Double couponInfo, BigDecimal skuPrice) {
        BigDecimal discountAmount = skuPrice.subtract(new BigDecimal(couponInfo));
        if (discountAmount.compareTo(BigDecimal.ZERO) < 1) return BigDecimal.ONE;
        return discountAmount;
    }

}

折扣

public class ZKCouponDiscount implements ICouponDiscount<Double> {


    /**
     * 折扣計算
     * 1. 使用商品價格乘以折扣比例,為最后支付金額
     * 2. 保留兩位小數(shù)
     * 3. 最低支付金額1元
     */
    public BigDecimal discountAmount(Double couponInfo, BigDecimal skuPrice) {
        BigDecimal discountAmount = skuPrice.multiply(new BigDecimal(couponInfo)).setScale(2, BigDecimal.ROUND_HALF_UP);
        if (discountAmount.compareTo(BigDecimal.ZERO) < 1) return BigDecimal.ONE;
        return discountAmount;
    }

}

N元購

public class NYGCouponDiscount implements ICouponDiscount<Double> {

    /**
     * n元購購買
     * 1. 無論原價多少錢都固定金額購買
     */
    public BigDecimal discountAmount(Double couponInfo, BigDecimal skuPrice) {
        return new BigDecimal(couponInfo);
    }

}
  • 以上是四種不同類型的優(yōu)惠券計算折扣金額的策略方式,可以從代碼中看到每一種優(yōu)惠方式的優(yōu)惠金額。

2.3 策略控制類

public class Context<T> {

    private ICouponDiscount<T> couponDiscount;

    public Context(ICouponDiscount<T> couponDiscount) {
        this.couponDiscount = couponDiscount;
    }

    public BigDecimal discountAmount(T couponInfo, BigDecimal skuPrice) {
        return couponDiscount.discountAmount(couponInfo, skuPrice);
    }

}
  • 策略模式的控制類主要是外部可以傳遞不同的策略實現(xiàn),在通過統(tǒng)一的方法執(zhí)行優(yōu)惠策略計算。
  • 另外這里也可以包裝成map結(jié)構(gòu),讓外部只需要對應(yīng)的泛型類型即可使用相應(yīng)的服務(wù)。

3. 測試驗證

3.1 編寫測試類(直減優(yōu)惠)

@Test
public void test_zj() {
    // 直減;100-10,商品100元
    Context<Double> context = new Context<Double>(new ZJCouponDiscount());
    BigDecimal discountAmount = context.discountAmount(10D, new BigDecimal(100));
    logger.info("測試結(jié)果:直減優(yōu)惠后金額 {}", discountAmount);
}

測試結(jié)果

15:43:22.035 [main] INFO  org.itstack.demo.design.test.ApiTest - 測試結(jié)果:直減優(yōu)惠后金額 90

Process finished with exit code 0

3.2 編寫測試類(滿減優(yōu)惠)

@Test
public void test_mj() {
    // 滿100減10,商品100元
    Context<Map<String,String>> context = new Context<Map<String,String>>(new MJCouponDiscount());
    Map<String,String> mapReq = new HashMap<String, String>();
    mapReq.put("x","100");
    mapReq.put("n","10");
    BigDecimal discountAmount = context.discountAmount(mapReq, new BigDecimal(100));
    logger.info("測試結(jié)果:滿減優(yōu)惠后金額 {}", discountAmount);
}

測試結(jié)果

15:43:42.695 [main] INFO  org.itstack.demo.design.test.ApiTest - 測試結(jié)果:滿減優(yōu)惠后金額 90

Process finished with exit code 0

3.3 編寫測試類(折扣優(yōu)惠)

@Test
public void test_zk() {
    // 折扣9折,商品100元
    Context<Double> context = new Context<Double>(new ZKCouponDiscount());
    BigDecimal discountAmount = context.discountAmount(0.9D, new BigDecimal(100));
    logger.info("測試結(jié)果:折扣9折后金額 {}", discountAmount);
}

測試結(jié)果

15:44:05.602 [main] INFO  org.itstack.demo.design.test.ApiTest - 測試結(jié)果:折扣9折后金額 90.00

Process finished with exit code 0

3.4 編寫測試類(n元購優(yōu)惠)

@Test
public void test_nyg() {
    // n元購;100-10,商品100元
    Context<Double> context = new Context<Double>(new NYGCouponDiscount());
    BigDecimal discountAmount = context.discountAmount(90D, new BigDecimal(100));
    logger.info("測試結(jié)果:n元購優(yōu)惠后金額 {}", discountAmount);

測試結(jié)果

15:44:24.700 [main] INFO  org.itstack.demo.design.test.ApiTest - 測試結(jié)果:n元購優(yōu)惠后金額 90

Process finished with exit code 0
  • 以上四組測試分別驗證了不同類型優(yōu)惠券的優(yōu)惠策略,測試結(jié)果是滿足我們的預(yù)期。
  • 這里四種優(yōu)惠券最終都是在原價100元上折扣10元,最終支付90元。

七、總結(jié)

  • 以上的策略模式案例相對來說不并不復(fù)雜,主要的邏輯都是體現(xiàn)在關(guān)于不同種類優(yōu)惠券的計算折扣策略上。結(jié)構(gòu)相對來說也比較簡單,在實際的開發(fā)中這樣的設(shè)計模式也是非常常用的。另外這樣的設(shè)計與命令模式、適配器模式結(jié)構(gòu)相似,但是思路是有差異的。
  • 通過策略設(shè)計模式的使用可以把我們方法中的if語句優(yōu)化掉,大量的if語句使用會讓代碼難以擴(kuò)展,也不好維護(hù),同時在后期遇到各種問題也很難維護(hù)。在使用這樣的設(shè)計模式后可以很好的滿足隔離性與和擴(kuò)展性,對于不斷新增的需求也非常方便承接。
  • 策略模式、適配器模式、組合模式等,在一些結(jié)構(gòu)上是比較相似的,但是每一個模式是有自己的邏輯特點,在使用的過程中最佳的方式是經(jīng)過較多的實踐來吸取經(jīng)驗,為后續(xù)的研發(fā)設(shè)計提供更好的技術(shù)輸出。

八、推薦閱讀

  • 1. 重學(xué) Java 設(shè)計模式:實戰(zhàn)工廠方法模式「多種類型商品不同接口,統(tǒng)一發(fā)獎服務(wù)搭建場景」
  • 2. 重學(xué) Java 設(shè)計模式:實戰(zhàn)原型模式「上機(jī)考試多套試,每人題目和答案亂序排列場景」
  • 3. 重學(xué) Java 設(shè)計模式:實戰(zhàn)橋接模式「多支付渠道(微信、支付寶)與多支付模式(刷臉、指紋)場景」
  • 4. 重學(xué) Java 設(shè)計模式:實戰(zhàn)組合模式「營銷差異化人群發(fā)券,決策樹引擎搭建場景」
  • 5. 重學(xué) Java 設(shè)計模式:實戰(zhàn)外觀模式「基于SpringBoot開發(fā)門面模式中間件,統(tǒng)一控制接口白名單場景」
  • 6. 重學(xué) Java 設(shè)計模式:實戰(zhàn)享元模式「基于Redis秒殺,提供活動與庫存信息查詢場景」
  • 7. 重學(xué) Java 設(shè)計模式:實戰(zhàn)備忘錄模式「模擬互聯(lián)網(wǎng)系統(tǒng)上線過程中,配置文件回滾場景」

    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多