1. 程式人生 > >## springboot 下策略模式的簡單使用

## springboot 下策略模式的簡單使用

1.靈魂三問

  • 接手前人(已跑路)專案快樂否?

  • 前人專案不寫註釋懵逼否?
  • 一個方法中一堆if/else,且業務判斷條件用簡單數字(或英文字母),不帶註釋,想打人否?

    所以,對於上述三個問題,我寫了此隨筆,然而————然並卵

    這篇文章並不能讓你不接手前人專案,並不能讓你看懂沒有註釋的業務程式碼,也並不能讓你以後不碰到if/else轟擊波,但是——系尬系

    魯迅先生曾倡導過,如果你覺得政府腐敗,那麼你就應該努力考取公務員從政,去內部解決腐敗;如果你覺得你的家鄉建設不夠美麗,那麼你應該去建設他;如果你覺得人民素質不夠高,那麼你應該提高自身素質,以身作則;如果你覺得這功能完全是業務無理取鬧,產品瞎接,那麼你應該——好吧,業務爸爸一切都好。

    瞎扯了半天,下面進入正題:

    很多情況下,都沒有一次到位得產品,也通常沒有一次到位的業務需求,所以在後期的功能擴充套件中,很可能會造成不停的對原始碼加入if/else分支判斷,來滿足新的業務需求,然而這對於後接手的程式設計師來說,在一堆if/else,幾百行程式碼中去快速理解邏輯,並加入擴充套件,無疑是件很蛋疼的事(好吧,其實我的真實原因是:看起來有點醜),所以,如何改造自己的if/else程式碼,讓其看的不顯臃腫,直觀簡潔,我百度了一下,簡單寫了份在springboot環境下,利用策略模式改造程式碼的隨筆,作為新知識的get體會!(好吧,策略模式其實很常見)

2.什麼是策略模式

    策略模式(Strategy Pattern):一個類的行為或其演算法可以在執行時更改。這種型別的設計模式屬於行為型模式。

    執行時隨時更改,有沒有想到spring的自動注入?靈活,易擴充套件這也是其特點之一。有沒有具體的實現步驟呢?有的!

3.簡單實現步驟

簡單的一個需求
  1. 首先,先假想一個簡單的業務——新需求上,這個功能暫時有三個分支判斷,三個分支對應不同的執行邏輯:

    • 1——孫悟空邏輯
    • 2——二師兄邏輯
    • 3——唐僧邏輯

    那麼,首先,我們當然可以用if/else,switch,來做分支判斷解決,好的解決,專案上線,後期擴充套件——

  • 業務A有發話了,我覺得應該有4——沙師弟邏輯,對吧,是這樣吧!好,我再加一個if,沒問題的!

  • 業務B突然有話發話了,我覺得應該有5——三隻眼邏輯,對吧,不能沒有二郎神啊!好,我再加一個if,ojbk

  • 業務C突然有想法了,咋不能忘了6——小白馬吧,對吧,這麼辛苦!嗯~~~,可以,應該可以快速實現!
  • 業務D又來了,我覺得那白骨精挺漂亮的,是吧?你(漂亮你大爺)!!!!!!!好,還有沒有漂亮的?

    所以,這個分支的類,看起來有點難受!

策略模式實現步驟

    好的話不多說,策略模式下,我們可以怎麼解決這個問題呢?

  1. 首先,可以建立一個列舉類,用於儲存分支判斷的條件(也可以用靜態變數)
public enum WestCommand {

    W_SuWuKong(1,"孫爺爺","monkeyCommand"),
    W_ZhuBaJie(2,"二師兄","pigCommand"),
    W_TangSeng(3,"和尚","monkCommand");
    private int value;

    private String descreption;

    private String beanName;

    private WestCommand(int value,String descreption,String beanName){
        this.value=value;
        this.descreption=descreption;
        this.beanName=beanName;
    }

    public int getValue(){
        return value;
    }

    public String getDescreption(){
        return descreption;
    }

    public String getBeanName(){
        return beanName;
    }
    public static WestCommand getInstance(int value) {
        for(WestCommand type : WestCommand.values()) {
            if(type.getValue() == value) {
                return type;
            }
        }
        return null;
    }

}

這個類用於儲存分支判斷條件,,,,,

  1. 建立策略角色介面
/**
 * @說明:
 * @型別名稱:StrategyCommand
 * @建立者: Raiden
 * @建立時間: 2020/2/11 12:01
 * @修改者: Raiden
 * @修改時間: 2020/2/11 12:01
 */
public interface StrategyCommand {


    String process();
}
  1. 建立具體策略角色

/**
 * @說明:唐僧
 * @型別名稱:MonkeyCommand
 * @建立者: Raiden
 * @建立時間: 2020/2/11 12:02
 * @修改者: Raiden
 * @修改時間: 2020/2/11 12:02
 */
@Service
public class MonkCommand implements StrategyCommand {
    @Override
    public String process() {
        return "和尚不曾調戲妖精了,施主還是別問了!!";
    }
}


/**
 * @說明:孫悟空
 * @型別名稱:MonkeyCommand
 * @建立者: Raiden
 * @建立時間: 2020/2/11 12:02
 * @修改者: Raiden
 * @修改時間: 2020/2/11 12:02
 */
@Service
public class MonkeyCommand implements StrategyCommand {
    @Override
    public String process() {
        return "你孫爺爺叫你回家吃飯了!!";
    }
}
/**
 * @說明:二師兄
 * @型別名稱:MonkeyCommand
 * @建立者: Raiden
 * @建立時間: 2020/2/11 12:02
 * @修改者: Raiden
 * @修改時間: 2020/2/11 12:02
 */
@Service
public class PigCommand implements StrategyCommand {
    @Override
    public String process() {
        return "你二師兄走位相當風騷!!";
    }
}
  1. 建立上下文,獲取具體角色

這裡首先需要建立一個spring的工具類,用於根據id獲取bean

/**
 * @說明:
 * @型別名稱:StrategeContext
 * @建立者: Raiden
 * @建立時間: 2020/2/11 14:41
 * @修改者: Raiden
 * @修改時間: 2020/2/11 14:41
 */
@Component
public class SpringUtils implements ApplicationContextAware {

    private static ApplicationContext context;

    @Override
    public void setApplicationContext(ApplicationContext   applicationContext) throws BeansException {
        if (SpringUtils.context==null){
            SpringUtils.context=applicationContext;
            System.out.println("初始化容器成功------------");
        }
    }
    //獲取context
    public static ApplicationContext getContext(){

        return SpringUtils.context;
    }

    //通過名稱獲取bean
    public static Object getBean(String beanName){

        return getContext().getBean(beanName);

    }

    /**
     * 通過型別獲取bean
     * @param tClass
     * @param <T>
     * @return
     */
    public static <T> T getBean(Class<T> tClass){

        return getContext().getBean(tClass);
    }

    public static <T> T getBean(String beanName,Class<T> classType){

        return getContext().getBean(beanName,classType);

    }

}

然後,建立上下文

/**
 * @說明:
 * @型別名稱:StrategyContext
 * @建立者: Raiden
 * @建立時間: 2020/2/11 15:05
 * @修改者: Raiden
 * @修改時間: 2020/2/11 15:05
 */
public class StrategyContext {


    /**
     * 獲取對應的command實現類
     * @param value
     * @param classType
     * @param <T>
     * @return
     */
    public static <T> T getStrategyBean(Integer value,Class<T> classType){
        return SpringUtils.getBean( 
                WestCommand.getInstance(value).getBeanName(),classType);

    }


}

在這裡,一切準備工作基本算是完成了,下面,我們來看看效果

這裡我是利用的springboot+springcloud建立了一個介面:

相應的控制層:

/**
 * @說明:
 * @型別名稱:StrategyCrtl
 * @建立者: Raiden
 * @建立時間: 2020/2/11 11:58
 * @修改者: Raiden
 * @修改時間: 2020/2/11 11:58
 */
@RestController
@RequestMapping("/strategy")
public class StrategyCrtl {


    @GetMapping("/{number}")
    public ResponseEntity<String> getMessage(@PathVariable Integer number){

        StrategyCommand bean = StrategyContext.getStrategyBean(number, StrategyCommand.class);

        return ResponseEntity.ok(bean.process());
    }
}

業務邏輯幹掉了if/else,啟動服務:

我們看一看看效果:1——孫悟空邏輯

2——二師兄邏輯

3——和尚邏輯

至於後來萬一需要漂亮的白骨精,那麼怎麼做相信不用我多說,這看起來確實比if/else美觀了不少,有人說差不多,那是因為業務爸爸層就只跟你說了一句話,萬一有幾百句呢