0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

什么是策略模式

科技綠洲 ? 來源:Java技術(shù)指北 ? 作者:Java技術(shù)指北 ? 2023-10-08 14:15 ? 次閱讀

什么是策略模式

官話: 策略模式(Strategy Pattern): 定義一系列算法類,將每一個(gè)算法封裝起來,并讓它們可以相互替換,策略模式讓算法獨(dú)立于使用它的客戶而變化。

簡(jiǎn)單理解就是,針對(duì)不同的場(chǎng)景,使用不同的策略進(jìn)行處理。

優(yōu)點(diǎn)

  1. 算法可以自由切換。
  2. 避免使用多重條件判斷。
  3. 擴(kuò)展性良好。

缺點(diǎn)

  1. 策略類會(huì)增多。
  2. 所有策略類都需要對(duì)外暴露。

使用場(chǎng)景

  1. 如果在一個(gè)系統(tǒng)里面有許多類,它們之間的區(qū)別僅在于它們的行為,那么使用策略模式可以動(dòng)態(tài)地讓一個(gè)對(duì)象在許多行為中選擇一種行為。
  2. 一個(gè)系統(tǒng)需要?jiǎng)討B(tài)地在幾種算法中選擇一種。
  3. 如果一個(gè)對(duì)象有很多的行為,如果不用恰當(dāng)?shù)哪J?,這些行為就只好使用多重的條件選擇語句來實(shí)現(xiàn)。

結(jié)構(gòu)圖

圖片
策略模式結(jié)構(gòu)圖

策略模式的簡(jiǎn)單示例

場(chǎng)景:最近太熱了,想要降降溫,有什么辦法呢

首先,定義一個(gè)降溫策略的接口

public interface CoolingStrategy {

    /**
     * 處理方式
     */
    void handle();

}

定義3種降溫策略;實(shí)現(xiàn)策略接口

public class IceCoolingStrategy implements CoolingStrategy {
    @Override
    public void handle() {
        System.out.println("使用冰塊降溫");
    }
}
public class FanCoolingStrategy implements CoolingStrategy {

    @Override
    public void handle() {
        System.out.println("使用風(fēng)扇降溫");
    }
}
public class AirConditionerCoolingStrategy implements CoolingStrategy {
    @Override
    public void handle() {
        System.out.println("使用空調(diào)降溫");
    }
}

定義一個(gè)降溫策略的上下文

public class CoolingStrategyContext {

    private final CoolingStrategy strategy;

    public CoolingStrategyContext(CoolingStrategy strategy) {
        this.strategy = strategy;
    }

    public void coolingHandle() {
        strategy.handle();
    }

}

測(cè)試

public class Main {
    public static void main(String[] args) {
        
        CoolingStrategyContext context = new CoolingStrategyContext(new FanCoolingStrategy());
        context.coolingHandle();

        context = new CoolingStrategyContext(new AirConditionerCoolingStrategy());
        context.coolingHandle();

        context = new CoolingStrategyContext(new IceCoolingStrategy());
        context.coolingHandle();
    }
}

運(yùn)行結(jié)果:

使用風(fēng)扇降溫
使用空調(diào)降溫
使用冰塊降溫

以上就是一個(gè)策略模式的簡(jiǎn)單實(shí)現(xiàn)

策略模式的項(xiàng)目實(shí)戰(zhàn)

場(chǎng)景

以我自己在工作中遇到的場(chǎng)景為例,《企業(yè)微信會(huì)話存檔》功能,獲取各種格式的消息內(nèi)容,進(jìn)行解析并保存數(shù)據(jù)。這里只針對(duì)消息處理的功能模塊,其他關(guān)于《企業(yè)微信會(huì)話存檔》的功能,有時(shí)間整理一下再發(fā)出來。

企業(yè)微信會(huì)話聊天會(huì)產(chǎn)生如下多種消息,在SpringBoot項(xiàng)目中應(yīng)該如何使用策略模式來完成消息的解析呢?

圖片
企業(yè)微信消息格式

獲取會(huì)話內(nèi)容 - API 看API內(nèi)容,數(shù)據(jù)都是json格式。思考應(yīng)該如何處理:

  1. 首先,既然要解析各種數(shù)據(jù),而每種數(shù)據(jù)格式結(jié)構(gòu)都不一樣,那么就需要先根據(jù)每種消息格式定義各自的對(duì)象,然后根據(jù)不同的需求,將json格式處理成pojo對(duì)象;
  2. 根據(jù)場(chǎng)景,需要定義兩個(gè)策略接口,一個(gè)是針對(duì)普通的文本格式消息的策略,另一個(gè)則是需要處理文件格式消息的策略;
  3. 定義策略處理上下文操作類,用于使用策略
  4. 每種消息,都會(huì)有一些相同的數(shù)據(jù),比如發(fā)送人、接收人、消息類型等;根據(jù)消息類型的不同,使用 key-value 的方式,讓調(diào)用者確定應(yīng)該使用哪個(gè)策略來處理數(shù)據(jù)

因?yàn)楦袷教?,這里只使用兩個(gè)格式作為例子

實(shí)現(xiàn)

兩個(gè)策略接口

public interface Strategy {
    /**
     * 處理會(huì)話存檔的內(nèi)容
     *
     * @param content json格式的消息內(nèi)容
     * @return 結(jié)果
     */
    < T > T handleContent(String content);
}
public interface MediaStrategy {
    /**
     * 處理會(huì)話存檔媒體內(nèi)容
     *
     * @param msgData 消息內(nèi)容
     */
    < T > void handleMedia(T msgData);
}

策略的具體實(shí)現(xiàn)(偽代碼)

@Component("link")
public class LinkStrategy implements Strategy {

    @Override
    public LinkPO handleContent(String content) {
        // JSON 轉(zhuǎn)換為具體對(duì)象
        LinkWrapDTO linkWrapDTO = JacksonUtils.json2Obj(content, LinkWrapDTO.class);
        // 將對(duì)象處理成業(yè)務(wù)需要的格式
        return Convert.convert(LinkPO.class, linkWrapDTO);
    }
}
@Component("image")
public class ImageStrategy implements Strategy, MediaStrategy {

    @Autowired
    private IMsgFileService msgFileService;

    @Override
    public ImagePO handleContent(String content) {
        // JSON 轉(zhuǎn)換為具體對(duì)象
        ImageWrapDTO imageWrapDTO = JacksonUtils.json2Obj(content, ImageWrapDTO.class);
        // 將對(duì)象處理成業(yè)務(wù)需要的格式
        return Convert.convert(ImagePO.class,imageWrapDTO);
    }

    @Override
    public < T > void handleMedia(T msgData) {
        // 將數(shù)據(jù)格式轉(zhuǎn)換為具體實(shí)現(xiàn)的數(shù)據(jù)格式
        ImagePO imagePo = Convert.convert(ImagePO.class, msgData);
        // 調(diào)用文件服務(wù),進(jìn)一步處理文件
        msgFileService.newFileTask(imagePo.getImage().getSdkfileid(),
                imagePo.getMsgid() + ".jpg", imagePo.getMsgid(), imagePo.getSeq(),
                imagePo.getImage().getFilesize(), imagePo.getImage().getMd5sum(), MessageEnum.IMAGE);
    }
}

策略上下文

@Component
public class StrategyContext {

    @Resource
    Map< String, Strategy > strategys = new ConcurrentHashMap<  >();

    @Resource
    Map< String, MediaStrategy > mediaStrategys = new ConcurrentHashMap<  >();

    public Strategy getStrategy(String component) {
        return strategys.get(component);
    }

    public MediaStrategy getMediaStrategy(String component) {
        return mediaStrategys.get(component);
    }
}

使用方式(偽代碼)

public class MsgService {
   @Resource
    private StrategyContext strategyContext;
    
    public void handlerMessage() {
        // 請(qǐng)求api獲取消息的json
        json = api();
        // 轉(zhuǎn)為通用格式對(duì)象
        basePo = JsonUtils.json2Obj(json, BasePO.class);
        // 選取不同的策略
        Strategy strategy = strategyContext.getStrategy(basePo.getMsgType());
        // 進(jìn)行處理
        strategy.handleContent(json);
        // 關(guān)于文件類消息的處理
        MediaStrategy mediaStrategy = strategyContext.getMediaStrategy(basePo.getMsgtype());
        if (null != mediaStrategy) {
            mediaStrategy.handleMedia(basePo);
        }
    }
}

以上就是策略模式的一種實(shí)現(xiàn)方式;

使用策略模式來處理不同格式的消息,雖然多了很多策略類,但是讓整個(gè)功能模塊的代碼變得清晰,松耦合,而且很容易擴(kuò)展和修改,并不會(huì)影響其他流程。

小結(jié)

從以上的例子很明顯的可以看出,策略模式的靈活性;如果此時(shí)企業(yè)微信提供了一種新的消息格式,那么根本無需修改之前的代碼,只需要再寫一個(gè)新的類,實(shí)現(xiàn)消息處理策略的接口,重寫處理方法即可;

了解策略模式的優(yōu)點(diǎn)和缺點(diǎn),合理的使用策略模式,會(huì)讓你的代碼更加的整潔優(yōu)雅。

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 接口
    +關(guān)注

    關(guān)注

    33

    文章

    8447

    瀏覽量

    150720
  • 數(shù)據(jù)
    +關(guān)注

    關(guān)注

    8

    文章

    6808

    瀏覽量

    88743
  • 算法
    +關(guān)注

    關(guān)注

    23

    文章

    4587

    瀏覽量

    92501
  • API
    API
    +關(guān)注

    關(guān)注

    2

    文章

    1472

    瀏覽量

    61749
收藏 人收藏

    評(píng)論

    相關(guān)推薦

    76 JavaScrip 面向?qū)ο缶幊?b class='flag-5'>模式實(shí)踐 策略模式

    前端javascript
    小凡
    發(fā)布于 :2022年08月28日 17:28:44

    #硬聲創(chuàng)作季 設(shè)計(jì)模式:談?wù)勀銓?duì)策略模式的理解

    python
    Mr_haohao
    發(fā)布于 :2022年10月16日 13:06:10

    關(guān)于LVOOP設(shè)計(jì)模式的框架問題?

    1. 請(qǐng)問目前的很多設(shè)計(jì)模式,比如簡(jiǎn)單工廠模式,策略模式之類的,labview是不是沒有框架,需要自己手工去實(shí)現(xiàn)?2. labview的actor framework是不是目前l(fā)abv
    發(fā)表于 08-07 23:14

    LABVIEW OOP 策略模式

    本帖最后由 meiyoudiandian 于 2020-5-18 21:59 編輯 《大話設(shè)計(jì)模式》這本書還是挺不錯(cuò)的,不知道出于什么原因,突然心血來潮,就想跟著寫寫。一章一章慢慢來,大家一同討論,共同進(jìn)步。沒有目的,沒有初衷,沒有情懷,只是素人。2020/05/18
    發(fā)表于 05-18 21:57

    C語言的策略模式提高了程序的可維護(hù)性和擴(kuò)展性

    設(shè)計(jì)模式,必定會(huì)在嚴(yán)謹(jǐn)?shù)鼐S護(hù)類層次上造成非常繁瑣和臃腫的代碼。這是因?yàn)镃++/java等自帶一套面向?qū)ο蟮墓ぞ?,而C語言要在代碼設(shè)計(jì)中,不斷地根據(jù)實(shí)際情況來創(chuàng)造面向?qū)ο蟮墓ぞ摺?因此對(duì)于文章的內(nèi)容,請(qǐng)大家主要關(guān)注、體會(huì)設(shè)計(jì)模式本身,更
    發(fā)表于 06-24 16:29 ?1139次閱讀

    不會(huì)有人不知道怎么優(yōu)雅的替換if-else語句吧

    三板斧手段: 優(yōu)先判斷條件,條件不滿足的,邏輯及時(shí)中斷返回; 融入策略模式; 策略模式+工廠+單例模式,錦上添花; 接
    的頭像 發(fā)表于 07-28 15:46 ?1399次閱讀
    不會(huì)有人不知道怎么優(yōu)雅的替換if-else語句吧

    設(shè)計(jì)模式 考試題+答案

    (Decorator) B策略模式(Strategy)C橋接模式(Bridge) D觀察者模式(Observer)轉(zhuǎn)存失敗重...
    發(fā)表于 11-07 10:20 ?39次下載
    設(shè)計(jì)<b class='flag-5'>模式</b> 考試題+答案

    Linux下CPU的手動(dòng)頻率設(shè)定 CPU電源策略模式

    http://www.51testing.com/html/20/n-3723920.html
    發(fā)表于 01-12 11:25 ?1次下載
    Linux下CPU的手動(dòng)頻率設(shè)定 CPU電源<b class='flag-5'>策略</b><b class='flag-5'>模式</b>

    設(shè)計(jì)模式最佳實(shí)踐探索—策略模式

    根據(jù)不同的應(yīng)用場(chǎng)景與意圖,設(shè)計(jì)模式主要分為創(chuàng)建型模式、結(jié)構(gòu)型模式和行為型模式三類。本文主要探索行為型模式中的
    的頭像 發(fā)表于 10-31 14:24 ?910次閱讀

    為什么我不再推薦枚舉策略模式?

    我們可以看到經(jīng)典方法,創(chuàng)建了一個(gè)接口、三個(gè)策略類,還是比較啰嗦的。調(diào)用類的實(shí)現(xiàn)也待商榷,新增一個(gè)策略類還要修改榜單實(shí)例(可以用抽象工廠解決,但是復(fù)雜度又上升了)。加之我們有更好的選擇,所以此處不再推薦經(jīng)典策略
    的頭像 發(fā)表于 04-14 10:52 ?1958次閱讀

    高頻使用的幾種設(shè)計(jì)模式

    策略模式定義了算法族,分別封裝起來,讓它們之間可以相互替換,此模式讓算法的變化獨(dú)立于使用算法的的客戶。這個(gè)策略模式的定義是不是有點(diǎn)抽象呢?那
    的頭像 發(fā)表于 05-08 09:57 ?933次閱讀
    高頻使用的幾種設(shè)計(jì)<b class='flag-5'>模式</b>

    介紹嵌入式C語言中策略模式的基本原理和實(shí)現(xiàn)方法

    嵌入式系統(tǒng)常常需要對(duì)不同的輸入采取不同的行為,例如按下按鈕后的操作、傳感器讀數(shù)后的處理、接收到的通信數(shù)據(jù)的解析等等。
    發(fā)表于 05-20 17:27 ?862次閱讀

    設(shè)計(jì)模式行為型:策略模式

    策略模式(Strategy Pattern)中,一個(gè)類的行為或其算法可以在運(yùn)行時(shí)更改。這種類型的設(shè)計(jì)模式屬于行為型模式。
    的頭像 發(fā)表于 06-07 11:18 ?624次閱讀
    設(shè)計(jì)<b class='flag-5'>模式</b>行為型:<b class='flag-5'>策略</b><b class='flag-5'>模式</b>

    迭代模式在UVM中的應(yīng)用有哪些

    行為型設(shè)計(jì)模式數(shù)量較多,上一篇介紹了模板模式策略模式,下面對(duì)迭代模式進(jìn)行介紹,挖掘其在UVM中的應(yīng)用。
    的頭像 發(fā)表于 08-14 17:15 ?572次閱讀
    迭代<b class='flag-5'>模式</b>在UVM中的應(yīng)用有哪些

    如何通過策略模式簡(jiǎn)化if-else

    相信大家日常開發(fā)中會(huì)經(jīng)常寫各種分支判斷語句,比如 if-else ,當(dāng)分支較多時(shí),代碼看著會(huì)比較臃腫,那么如何優(yōu)化呢? 1、什么是策略模式? Define a family
    的頭像 發(fā)表于 10-08 16:08 ?705次閱讀
    如何通過<b class='flag-5'>策略</b><b class='flag-5'>模式</b>簡(jiǎn)化if-else