Springboot整合策略模式概念->使用場景->優缺點->企業級實戰

2023-01-06 12:00:24

一、前言

策略模式可能是在工作中使用最多的,也是在面試中最常提到的,程式碼重構和優化的必備!
小編之前也是一直說,其實沒有真正的實戰;最近有了機會實戰了一下,來分享一下使用心得和在企業級的使用!

二、策略模式

1. 什麼是策略模式

策略模式,英文全稱是 Strategy Design Pattern。在 GoF 的《設計模式》一書中,它是這樣定義的:

定義一族演演算法類,將每個演演算法分別封裝起來,讓它們可以互相替換。策略模式可以使演演算法的變化獨立於使用它們的使用者端(這裡的使用者端代指使用演演算法的程式碼)。

2. 策略模式結構組成

  • Strategy:抽象策略類,一般為介面或者策略類
  • ConcreteStrategy:具體演演算法實現策略類
  • Context:環境或者上下文類,用於統一執行具體策略

其實以上三部分用白話文來解釋就是:
需要一個介面和策略進行規範和約束介面和方法,這時需要一些具體的實現演演算法類去繼承或者實現剛剛的介面和策略,最後通過一個環境或者上下文,也可以叫做工廠根據型別進行呼叫具體的演演算法!

3. 使用場景

  • 避免冗長的 if-else 或 switch 分支判斷
  • 需要動態地在幾種演演算法中選擇一種
  • 對客戶隱藏具體策略 (演演算法) 的實現細節,彼此完全獨立,擴充套件其餘不受影響

具體場景一般為:

  • 支付方式選擇
  • 打折、滿減方式選擇
  • 根據型別呼叫不同的系統

4. 優缺點

優點:

  • 擴充套件性好
  • 符合開閉原則
  • 符合單一職責原則
  • 可讀性好
  • 便於維護
  • 避免多層判斷

缺點:

  • 策略過多,導致策略類
  • 對新手讀程式碼不友好

三、策略模式實戰

1. 實戰例子

今天小編根據春夏秋冬四季需要做不同的事情來演示一下策略模式的使用方案;
需求是:
如果是春天,就要去放風箏
如果是夏天,就要去游泳
如果是秋天,就要去看楓葉
如果是冬天,就要去打雪仗
沒有使用策略模式的話,肯定就是
if-if else進行實現!
下面就帶大家體會一下具體使用哈!!

2. 策略介面

/**
 * 四季策略
 * @author wangzhenjun
 * @date 2022/12/1 9:30
 */
public interface SeasonsStrategy {

    /**
     * 根據季節去執行不同的方案
     * @param seasons
     * @return
     */
    String execute(String seasons);
}

3. 春季具體實現

/**
 * 春季具體實現
 * @author wangzhenjun
 * @date 2022/12/1 9:34
 */
// 指定容器的名稱,不指定預設為類名稱首字母小寫
@Component("spring")
public class SpringStrategy implements SeasonsStrategy{
    @Override
    public String execute(String seasons) {

        return seasons + "來了!我們一起去放風箏吧!";
    }
}

4. 夏季具體實現

/**
 * 夏季具體實現
 * @author wangzhenjun
 * @date 2022/12/1 9:34
 */
// 指定容器的名稱,不指定預設為類名稱首字母小寫
@Component("summer")
public class SummerStrategy implements SeasonsStrategy{
    @Override
    public String execute(String seasons) {

        return seasons + "來了!我們一起去游泳吧!";
    }
}

5. 秋季具體實現

/**
 * 秋季具體實現
 * @author wangzhenjun
 * @date 2022/12/1 9:34
 */
// 指定容器的名稱,不指定預設為類名稱首字母小寫
@Component("autumn")
public class AutumnStrategy implements SeasonsStrategy{
    @Override
    public String execute(String seasons) {

        return seasons + "來了!我們一起去放看楓葉吧!";
    }
}

6. 冬季具體實現

/**
 * 冬季具體實現
 * @author wangzhenjun
 * @date 2022/12/1 9:34
 */
// 指定容器的名稱,不指定預設為類名稱首字母小寫
@Component("winter")
public class WinterStrategy implements SeasonsStrategy{
    @Override
    public String execute(String seasons) {

        return seasons + "來了!我們一起去打雪仗吧!";
    }
}

7. 上下文工廠實現

private Map<String, SeasonsStrategy> seasonsMap;這是最重要的,很多時候我們都知道怎麼進行策略和實現怎麼寫,不知道怎麼統一去放進去,來進行呼叫,可以自己放在map中。當然spring已經給我們組裝好了,只要按需呼叫即可!

核心:
Spring會自動將Strategy介面的實現類注入到這個Map中,key為bean id,value值則為對應的策略實現類!

/**
 * 環境或者上下文類,用於統一執行具體策略
 * @author wangzhenjun
 * @date 2022/12/1 9:56
 */
@Component
public class SeasonsFactory {
    /**
     * Spring會自動將Strategy介面的實現類注入到這個Map中,key為bean id,value值則為對應的策略實現類
     */
    @Autowired
    private Map<String, SeasonsStrategy> seasonsMap;

    /**
     * 處理四季統一入口方法
     * @param seasons
     * @param beanName
     * @return
     */
    public String handle(String seasons,String beanName){
    	// 根據bean的名稱獲取對應的演演算法處理類
        SeasonsStrategy seasonsStrategy = seasonsMap.get(beanName);
        String execute = seasonsStrategy.execute(seasons);
        return execute;
    }
}

8. controller處理

@Slf4j
@RestController
@RequestMapping("/test")
public class TestController {
	
    @Autowired
    private SeasonsFactory seasonsFactory;

    @GetMapping("/strategyTest/{seasons}/{beanName}")
    public Result strategyTest(@PathVariable("seasons") String seasons,@PathVariable("beanName") String beanName){
        String handle = seasonsFactory.handle(seasons, beanName);
        return Result.success(handle);
    }
}

9. 測試

http://localhost:8087/test/strategyTest/春天/spring

http://localhost:8087/test/strategyTest/夏天/summer

四、總結

在策略模式中定義了一系列演演算法,將每一個演演算法封裝起來,並讓它們可以相互替換,互不影響。

策略模式得益於按照開閉原則進行設計,各個具體演演算法按照單一職責原則設計; 提高了程式碼的複用性,對客戶隱藏具體策略 (演演算法) 的實現細節,彼此完全獨立,擴充套件其餘不受影響;避免if-else 或 switch 分支語句判斷;其缺點在於使用者端必須知道所有的策略類,增加了系統中類的個數。

在日常開發一般用於消除多重判斷,有時候不要為了用設計模式而用設計模式,一定要結合業務場景,過度設計也是很致命的!!

如果對你有幫助,還請不要吝嗇您的發財小手,你的一鍵三連是我寫作的動力,謝謝大家哈!!


可以看下小編的微信公眾號,文章首發看,歡迎關注,一起交流哈!!