模板、策略以及工厂模式

2022-08-31 00:00:00 模式 算法 测试 方法 策略

记录学习过程中的问题,实操总结,方便回顾。

模板方法

属于行为设计模式;
在父类中定义一个算法的框架,允许子类在不修改结果的情况下重写算法的特定步骤。
应用场景:当多个产品中的某一功能的处理重复,那么我们可以将重复的流程单独做成类方法(父类),然后针对每个产品继承父类并实现对应方法来适配不同的产品内部执行需求(子类)。

上述爬取不同网站的的数据,但是爬取和提取数据的流程一样,那么我们将重复的流程封装为父类方法,并实现。
好处:如果后续新加入不同产品的相同功能,那么可以直接拿来使用。
测试代码:

/**
注意使用京东类的时候进行了向上转型
*/
@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设计模式

相关文章