模板、策略以及工廠模式

2022-08-31 06:00:33

記錄學習過程中的問題,實操總結,方便回顧。

模板方法

屬於行為設計模式;
在父類別中定義一個演演算法的框架,允許子類在不修改結果的情況下重寫演演算法的特定步驟。
應用場景:當多個產品中的某一功能的處理重複,那麼我們可以將重複的流程單獨做成類方法(父類別),然後針對每個產品繼承父類別並實現對應方法來適配不同的產品內部執行需求(子類)。

上述爬取不同網站的的資料,但是爬取和提取資料的流程一樣,那麼我們將重複的流程封裝為父類別方法,並實現。
好處:如果後續新加入不同產品的相同功能,那麼可以直接拿來使用。
測試程式碼:

/**
注意使用京東類的時候進行了向上轉型
*/
@Test
    public void demo(){
        NetMall netMall = new JDNetMall("1000001","*******");
        String base64 = netMall.generateGoodsPoster("https://item.jd.com/100008348542.html");
        log.info("測試結果:{}", base64);
    }

模板模式地址

策略模式

屬於行為設計模式;
其能讓你定義一系列演演算法並將每種演演算法分別放入獨立的類中,以使演演算法的物件能夠互換;
好處:能夠替代大量if-else的利器;
場景:一般是具有同類可替代的行為邏輯演演算法場景;不同型別的交易方式(信用卡、支付寶、微信)、生成唯一ID策略(UUID、DB自增、DB+Redis、雪花演演算法、Leaf演演算法),導航軟體(公路路線,步行路線,高速路線)等,都可以使用策略模式進行行為包裝,供給外部使用;
其使用的核心點建立一個上下文策略類(策略控制器),並且必須包含一個成員變數來儲存對於每種策略的引入:

/**
 * @author xbhog
 * @describe:策略控制器
 * @date 2022/8/21
 */
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);
    }
}

通過構造方法來結構傳遞來的具體的策略,並呼叫計算介面。(真的很巧妙!!)上下文策略不負責選擇具體的演演算法,相當於中間站,提供一個小屋來進行互動。

上下文策略使用的好處:上下文可獨立於具體策略。這樣你就可在不修改上下文程式碼或其他策略的情況下新增新演演算法或修改已有演演算法了。
看下測試(細品):

/**
     * 測試策略模式
     */
@Test
public void Strategy_mj(){
    Context<Map<String, String>> mjActivity = new Context<>(new MJCouponDiscount());
    HashMap<String, String> map = new HashMap<>();
    map.put("x","100");
    map.put("y","10");
    BigDecimal discountAmount = mjActivity.discountAmount(map, new BigDecimal(100));
    log.info("測試結果,滿減優惠後的金額:{}",discountAmount);
}
@Test
public void Strategy_zj(){
    Context<Double> context = new Context<>(new ZjCouponDiscount());
    BigDecimal discountAmount = context.discountAmount(9D, new BigDecimal(100));
    log.info("測試結果,直減優惠後的金額:{}",discountAmount);
}
@Test
public void Strategy_zk(){
    Context<Double> context = new Context<>(new ZKCouponDiscount());
    BigDecimal discountAmount = context.discountAmount(0.8D, new BigDecimal(100));
    log.info("測試結果,折扣優惠後的金額:{}",discountAmount);
}
@Test
public void Strategy_nyg(){
    Context<Double> context = new Context<>(new NYGCouponDiscount());
    BigDecimal discountAmount = context.discountAmount(80D, new BigDecimal(100));
    log.info("測試結果,N元購優惠後的金額:{}",discountAmount);
}

策略模式地址

工廠方法模式

屬於建立型設計模式;
工廠模式在父類別中提供一個建立物件的方法,允許子類決定範例化物件的型別;
好處:提供程式碼的擴充套件性,減少if-else方法
場景:

  1. 當我們需要替換新的物件時,但是在不同的產品或功能中都引入了,造成修改困難;(簡單工廠模式,但功能過多時,會造成過多的if-else)
  2. 當我們需要增加新的物件,比如獎品(兌換卡,實物商品,優惠卷)或者紀錄檔框架等型別的場景(工廠方法模式)

工廠方法模式的核心:調整物件建立時的位置,但是需要注意的是,僅當這些產品(兌換卡,實物商品,優惠卷)具有相同的父類別或者介面時,子類才能返回不同型別的產品,同時父類別中的工廠方法還應將其返回型別宣告為這一共有介面(每個產品具有共同的方法);
參考圖如下:

細品測試:

/**
     * 工廠模式
     * @throws Exception
     */
    @Test
    public void  test_commodity() throws Exception{
        StoreFactory storeFactory = new StoreFactory();
        ICommodity commodityService = storeFactory.getCommodityService(3);
        commodityService.sendCommodity("10001","AQY1xjkUodl8LO975GdfrYUio",null,null);
    }
    @Test
    public void Test_coupon() throws Exception {
        StoreFactory storeFactory = new StoreFactory();
        ICommodity commodityService = storeFactory.getCommodityService(1);
        commodityService.sendCommodity("10001", "EGM1023938910232121323432", "791098764902132", null);
    }
    @Test
    public void Test_Goods() throws Exception {
        StoreFactory storeFactory = new StoreFactory();
        ICommodity commodityService = storeFactory.getCommodityService(2);
        HashMap<String, String> extMap = new HashMap<>();
        extMap.put("consigneeUserName", "謝飛機");
        extMap.put("consigneeUserPhone", "15200292123");
        extMap.put("consigneeUserAddress", "吉林省.長春市.雙陽區.XX街道.檀溪苑小區.#18-2109");
        commodityService.sendCommodity("10001","9820198721311","1023000020112221113",extMap);
    }

推薦部落格
工廠方法模式地址

參考和學習參照

深入設計模式(亞歷山大·什韋茨)
重學Java設計模式