<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          后端思維篇:如何應(yīng)用設(shè)計(jì)模式優(yōu)化代碼

          共 6587字,需瀏覽 14分鐘

           ·

          2022-06-01 01:00

          前言

          大家好,我是撿田螺的小男孩。

          本文是后端思維專(zhuān)欄的第三篇哈,本文內(nèi)容就是:在原有代碼基礎(chǔ)上,如何一步步通過(guò)設(shè)計(jì)模式去優(yōu)化代碼?日常工作中,我們用得最多的設(shè)計(jì)模式,就是策略模式、工廠(chǎng)模式和模板方法模式啦。最近剛好用這幾種模式優(yōu)化了代碼,所以今天跟大家聊聊,我是怎么優(yōu)化的,思路是怎么樣的。希望本文對(duì)大家有幫助哈

          1. 優(yōu)化前偽代碼的流程
          2. 策略模式是如何應(yīng)用進(jìn)去的
          3. 工廠(chǎng)設(shè)計(jì)模式是怎么使用的
          4. 模板方法模式又是怎么應(yīng)用進(jìn)去的。
          5. 嘮叨幾句

          1. 優(yōu)化前偽代碼流程

          大家先看下,優(yōu)化前,原有代碼的大概邏輯哈。代碼如下:

          class?Parameter{
          ????int?pageSize;
          ????int?pageNo;
          ??? int reqNum;
          ????//其他參數(shù)。
          }

          //邏輯處理,是否命中客群
          boolean?isMarketHit(Parameter?dto){
          ????//如果是企業(yè)客群類(lèi)型
          ????if(dto.type?==?'enterprise'){
          ???????
          ???????//開(kāi)關(guān)關(guān)閉不請(qǐng)求
          ???????if(isEnterpriseSwitchClose){
          ??????????return?false;???????????
          ???????}
          ???????
          ????????//請(qǐng)求只有一條記錄的話(huà)
          ????????if(dto.reqNum==1){
          ????????????//調(diào)用大數(shù)據(jù)的點(diǎn)查接口
          ????????????return?singleRemoteEOIinvoke(dto);?
          ????????????
          ????????????//請(qǐng)求超過(guò)一條的話(huà)
          ????????}else?if(dto.reqNum>1){
          ????????
          ????????????//調(diào)用大數(shù)據(jù)的批量接口
          ????????????return?batchRemoteEOIinvoke(dto);????
          ????????}
          ????????
          ????????//如果是市場(chǎng)營(yíng)銷(xiāo)類(lèi)型
          ????}else?if(dto.type=='market_list'){
          ????
          ??????//開(kāi)關(guān)關(guān)閉不請(qǐng)求
          ???????if(isMarketListSwitchClose){
          ??????????return?false;???????????
          ???????}
          ????????//請(qǐng)求只有一條記錄的話(huà)
          ????????if(dto.reqNum==1){
          ????????????//調(diào)用營(yíng)銷(xiāo)的點(diǎn)查接口
          ????????????return?singleRemoteMarketinvoke(dto);??
          ???????????
          ??????????//請(qǐng)求超過(guò)一條的話(huà)
          ????????}else?if(dto.reqNum>1){
          ????????????//調(diào)用營(yíng)銷(xiāo)的批量接口
          ????????????return?batchRemoteMarketinvoke(dto);????
          ????????}
          ????}
          }

          這個(gè)代碼可能存在哪些問(wèn)題呢?

          • 如果if分支變多的話(huà),代碼就會(huì)變得臃腫
          • 如果你需要接入一種新的類(lèi)型,只能在源代碼修改

          說(shuō)得專(zhuān)業(yè)一點(diǎn)點(diǎn),就是以上代碼,違背了面向?qū)ο蟮?strong>開(kāi)閉原則和單一原則。

          • 開(kāi)閉原則:(對(duì)于擴(kuò)展是開(kāi)放的,對(duì)于修改是封閉的),增加或者刪除某個(gè)邏輯,都需要修改原來(lái)的代碼
          • 單一原則:(規(guī)定一個(gè)類(lèi)應(yīng)該只有一個(gè)發(fā)生變化的原因),修改任何類(lèi)型的分支邏輯代碼,都需要修改當(dāng)前類(lèi)的代碼

          2. 策略模式是如何應(yīng)用進(jìn)去的

          大家是否還記得,如果代碼中有多個(gè)if...else等條件分支,并且每個(gè)條件分支,可以封裝起來(lái)替換的,我們就可以使用策略模式來(lái)優(yōu)化。

          回憶一下,什么是策略模式呢?

          策略模式定義了算法族,分別封裝起來(lái),讓它們之間可以相互替換,此模式讓算法的變化獨(dú)立于使用算法的的客戶(hù)。這個(gè)策略模式的定義是不是有點(diǎn)抽象呢?打個(gè)通俗易懂的比喻:

          假設(shè)你跟不同性格類(lèi)型的小姐姐約會(huì),要用不同的策略,有的請(qǐng)電影比較好,有的則去吃小吃效果不錯(cuò),有的去逛街買(mǎi)買(mǎi)買(mǎi)最合適。當(dāng)然,目的都是為了得到小姐姐的芳心,請(qǐng)看電影、吃小吃、逛街就是不同的策略。

          策略模式針對(duì)一組算法,將每一個(gè)算法封裝到實(shí)現(xiàn)共同接口的不同獨(dú)立的類(lèi)中,從而使得它們可以相互替換。策略模式我們一般是怎么定義的呢?

          • 一個(gè)接口或者抽象類(lèi),里面兩個(gè)方法(一個(gè)方法匹配類(lèi)型,一個(gè)可替換的邏輯實(shí)現(xiàn)方法)
          • 不同策略的差異化實(shí)現(xiàn)(就是說(shuō),不同策略的實(shí)現(xiàn)類(lèi))

          所以,對(duì)于原有的偽代碼流程,我們就可以定義企業(yè)客群類(lèi)型的策略實(shí)現(xiàn)類(lèi),和市場(chǎng)營(yíng)銷(xiāo)類(lèi)型的策略實(shí)現(xiàn)類(lèi)。這兩個(gè)策略實(shí)現(xiàn)類(lèi)都實(shí)現(xiàn)了兩個(gè)方法,一個(gè)方法是匹配類(lèi)型的,就是返回原始代碼if...else條件判斷的類(lèi)型;然后另外個(gè)方法,就是if...else條件的實(shí)現(xiàn)內(nèi)容。代碼如下:

          //一個(gè)接口
          interface?IGroupLabelStrategyService?{

          ????//這個(gè)方法對(duì)應(yīng)策略實(shí)現(xiàn)類(lèi)的具體實(shí)現(xiàn)
          ????boolean?processBiz(Parameter?dto);
          ????
          ????//這個(gè)方法就是策略類(lèi)的類(lèi)型,也就是對(duì)應(yīng)```if...else```條件判斷的類(lèi)型
          ????String?getType();
          }?

          //企業(yè)客群類(lèi)型的策略實(shí)現(xiàn)類(lèi)
          EnterpriseGroupLablelStrategyServiceImpl?implements?IGroupLabelStrategyService{
          ????
          ????//對(duì)應(yīng)企業(yè)客群類(lèi)型的條件分支里面的實(shí)現(xiàn)
          ????boolean?processBiz(Parameter?dto){
          ????
          ?????????//開(kāi)關(guān)關(guān)閉不請(qǐng)求
          ???????if(isEnterpriseSwitchClose){
          ??????????return?false;???????????
          ???????}
          ??????
          ????????//請(qǐng)求只有一條記錄的話(huà)
          ????????if(dto.reqNum==1){
          ????????????//調(diào)用大數(shù)據(jù)的點(diǎn)查接口
          ????????????return?singleRemoteEOIinvoke(dto);?
          ????????????
          ????????????//請(qǐng)求超過(guò)一條的話(huà)
          ????????}else?if(dto.reqNum>1){
          ????????
          ????????????//調(diào)用遠(yuǎn)程大數(shù)據(jù)批量接口
          ????????????return?batchRemoteEOIinvoke(dto);????
          ????????}
          ????????
          ?????}
          ?????
          ????//對(duì)應(yīng)企業(yè)類(lèi)型
          ????String?getType(){
          ???????return?"enterprise";
          ????}
          }

          //市場(chǎng)營(yíng)銷(xiāo)類(lèi)型的策略實(shí)現(xiàn)類(lèi)
          MarketListGroupLablelStrategyServiceImpl?implements?IGroupLabelStrategyService{

          ?????//對(duì)應(yīng)市場(chǎng)營(yíng)銷(xiāo)類(lèi)型的條件分支里面的實(shí)現(xiàn)
          ?????boolean?processBiz(Parameter?dto){
          ?????
          ???????//開(kāi)關(guān)關(guān)閉不請(qǐng)求
          ???????if(isMarketListSwitchClose){
          ??????????return?false;???????????
          ???????}
          ???????
          ????????//請(qǐng)求只有一條記錄的話(huà)
          ????????if(dto.reqNum==1){
          ????????????//調(diào)用營(yíng)銷(xiāo)點(diǎn)查接口
          ????????????return?singleRemoteMarketinvoke(dto);??
          ???????????
          ??????????//請(qǐng)求超過(guò)一條的話(huà)
          ????????}else?if(dto.reqNum>1){
          ????????????//調(diào)用營(yíng)銷(xiāo)批量接口
          ????????????return?batchRemoteMarketinvoke(dto);????
          ????????}
          ????????
          ??????}
          ??????
          ??????String?getType(){
          ?????????return?"market_list";
          ???????}
          }

          3. 工廠(chǎng)設(shè)計(jì)模式是怎么使用的

          每個(gè)策略現(xiàn)在都實(shí)現(xiàn)好了,不同策略的實(shí)現(xiàn)類(lèi)怎么交給spring管理呢?

          我們可以實(shí)現(xiàn)ApplicationContextAware接口,把策略的實(shí)現(xiàn)類(lèi)注入到一個(gè)map,然后根據(jù)請(qǐng)求方不同的策略請(qǐng)求類(lèi)型,去實(shí)現(xiàn)不同的調(diào)用嘛,其實(shí)就是類(lèi)似于工廠(chǎng)模式的思想啦。代碼如下:

          @Component
          public?class?GroupLabelStrategyServiceFactory?implements?ApplicationContextAware{

          ????//存放對(duì)應(yīng)的類(lèi)型和實(shí)現(xiàn)類(lèi)
          ????private?Map?map?=?new?ConcurrentHashMap<>();
          ????
          ????//策略實(shí)現(xiàn)類(lèi)注入到map
          ????@Override
          ????public?void?setApplicationContext(ApplicationContext?applicationContext)?throws?BeansException?{
          ????????Map?tempMap?=?applicationContext.getBeansOfType(IGroupLabelStrategyService.class);
          ????????
          ????????tmepMap.values().forEach(strategyService?->?map.put(strategyService.getType(),?strategyService));
          ????}
          ????
          ????//工廠(chǎng)方法
          ????public?boolean?processBiz(ParamDTO?dto){
          ????
          ????????//根據(jù)不同類(lèi)型,獲取不同的實(shí)現(xiàn)類(lèi)
          ????????IGroupLabelStrategyService?groupLabelStrategyService=?map.get(dto.getType());
          ????????
          ????????if?(batchGroupLabelJudgeService?!=?null)?{
          ????????????return?groupLabelStrategyService.processBiz(dto);
          ????????}
          ????????return?false;?????
          ?????}?
          }

          有了策略模式+工廠(chǎng)方法模式后,我們偽代碼流程簡(jiǎn)化成這樣啦:

          class?Parameter{
          ????int?pageSize;
          ????int?pageNo;
          ??? int reqNum;
          ????//其他參數(shù)。
          }

          boolean?isMarketHit(Parameter?dto){
          ??//直接調(diào)用工廠(chǎng)類(lèi)就可以啦,其他邏輯處理已經(jīng)在策略實(shí)現(xiàn)類(lèi)里面了。
          ??return?groupLabelStrategyServiceFactory.processBiz(dto);
          }

          4. 模板方法模式又是怎么應(yīng)用進(jìn)去的

          小伙伴們,細(xì)心回頭觀(guān)察下原先的偽代碼流程,會(huì)發(fā)現(xiàn)一個(gè)共性的代碼流程,就是先開(kāi)關(guān)控制,然后根據(jù)請(qǐng)求數(shù)量決定走單筆調(diào)用還是批量調(diào)用。

          這就可以使用模板方法繼續(xù)優(yōu)化了。所謂模板方法模式,其實(shí)就是:

          定義一個(gè)操作中的算法的骨架流程,而將一些步驟延遲到子類(lèi)中,使得子類(lèi)可以不改變一個(gè)算法的結(jié)構(gòu)即可重定義該算法的某些特定步驟。它的核心思想就是:定義一個(gè)操作的一系列步驟,對(duì)于某些暫時(shí)確定不下來(lái)的步驟,就留給子類(lèi)去實(shí)現(xiàn),這樣不同的子類(lèi)就可以定義出不同的步驟。

          為了通俗易懂一點(diǎn),打個(gè)比喻:

          追女朋友要先“牽手”,再“擁抱”,再“接吻”, 再“拍拍..額..手”。至于具體你用左手還是右手牽,無(wú)所謂,但是整個(gè)過(guò)程,定了一個(gè)流程模板,按照模板來(lái)就行。

          模板方法使用比較簡(jiǎn)單:

          • 一個(gè)抽象類(lèi),定義骨架流程(抽象方法放一起)
          • 確定的共同方法步驟,放到抽象類(lèi)(去除抽象方法標(biāo)記)
          • 不確定的步驟,給子類(lèi)去差異化實(shí)現(xiàn)

          我們只需要把開(kāi)關(guān)控制接口,單筆遠(yuǎn)程調(diào)用、批量遠(yuǎn)程調(diào)用這個(gè)通用共性的流程,定義到模板抽象類(lèi)就好啦。代碼如下:

          public?abstract??AbstractGroupLabelJudgeTemplate?implements?IGroupLabelStrategyService{
          ?????????//模板骨架
          ?????????public?boolean?processBiz(Parameter?dto){
          ??????????????if(isSwitchClose){
          ?????????????????return?false;
          ??????????????}
          ?????????????if(dto.reqNum==1){
          ?????????????????return?singleRemote(dto);
          ?????????????}else?if(dto.reqNum>1){
          ?????????????????return?batchRemote(dto);
          ????????????}
          ?????????}
          ???????//開(kāi)關(guān)由子類(lèi)控制
          ????????abstract?boolean?isSwitchClose();
          ????????//單筆遠(yuǎn)程調(diào)用,由子類(lèi)控制
          ????????astract?boolean?singleRemote(dto);
          ????????//批量遠(yuǎn)程調(diào)用,由子類(lèi)控制
          ????????astract?boolean?batchRemote(dto);
          }

          不同的策略子類(lèi)自己控制開(kāi)關(guān),和控制不同接口的調(diào)用即可。

          EnterpriseGroupLablelStrategyServiceImpl?extends?AbstractGroupLabelJudgeTemplate{
          ?????boolean?isSwitchClose(){
          ?????????//企業(yè)客群開(kāi)關(guān)
          ?????}
          ?????boolean?singleRemote(ParamDTO?dto){
          ????????//企業(yè)客群?jiǎn)喂P調(diào)用?????
          ????????return?singleRemoteEOIinvoke(dto);????
          ????}
          ????boolean?batchRemote(ParamDTO?dto){
          ??????//企業(yè)客群批量調(diào)用???
          ??????return?batchRemoteEOIinvoke(dto);
          ???}????????
          }
          MarketListGroupLablelStrategyServiceImpl?extends?AbstractGroupLabelJudgeTemplate{
          ?????boolean?isSwitchClose(){
          ?????????//營(yíng)銷(xiāo)客群開(kāi)關(guān)
          ?????}
          ?????boolean?singleRemote(ParamDTO?dto){
          ????????//營(yíng)銷(xiāo)客群?jiǎn)喂P調(diào)用?????
          ????????return?singleRemoteMarketinvoke(dto);????
          ????}
          ????boolean?batchRemote(ParamDTO?dto){
          ??????//營(yíng)銷(xiāo)客群批量調(diào)用???
          ??????return?batchRemoteMarketinvoke(dto);
          ???}????????
          }

          5. 嘮叨幾句

          策略模式、工廠(chǎng)模式和模板方法模式這三種設(shè)計(jì)模式,是日常開(kāi)發(fā)用得最多的。本文呢,也是闡述了我是如何在原有代碼上,抽取出設(shè)計(jì)模式的。大家可以應(yīng)用到自己的工作中去哈,如果還沒(méi)理解的話(huà),可以加我微信,回復(fù)加群,拉你進(jìn)學(xué)習(xí)群,跟群上小伙伴一起探討。


          推薦閱讀:

          兩萬(wàn)字詳解!InnoDB鎖專(zhuān)題!

          阿里一面:SQL 優(yōu)化有哪些技巧?

          面試官:策略模式和代理模式有什么區(qū)別?



          歡迎關(guān)注微信公眾號(hào):互聯(lián)網(wǎng)全棧架構(gòu),收取更多有價(jià)值的信息。

          瀏覽 33
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  日韩一级 片中文字幕 | 啪啪视频在线观看入口 | 8av在线观看 | 亚洲AV电影免费在线观看 | 国产性爱无码视频 |