主頁 > 軟體設計 > 80%的程式員都不知道java的策略模式

80%的程式員都不知道java的策略模式

2020-11-25 12:25:49 軟體設計

在講策略模式之前,我先來講一下我作業中遇到的一個案例:

Demo

作業中有一個專案是協同辦公軟體,里面有一個動態功能,需要將客戶對專案的不同操作的動態即時同步出來,假設有以下四個動態:新增了xx專案,更新了xx專案,洗掉了xx專案,還原了xx專案,

如果是有你來做,你會怎么做?

整理了最新2020整理收集的一線互聯網公司面試真題(都整理成檔案),有很多干貨,包含netty,spring,執行緒,spring cloud等詳細講解,也有詳細的學習規劃圖,面試題整理等,我感覺在面試這塊講的非常清楚:

有需要的小伙伴可以戳這里免費領取,暗號:CSDN

在這里插入圖片描述
在這里插入圖片描述

我們很有可能寫出下面的代碼:

 
public class Message {
 
    public void changeMessage(int flag){
        if (flag.equals(MessageEnum.PROJECT_UPDATE.getCode())){
                // 動態顯示:更新了xx專案
                messageEntity.setContent(userName+MessageEnum.PROJECT_UPDATE.getMessage()+" "+message.getName());
                messageEntity.setSource(MessageSourceEnum.SOURCE_PROJECT.getCode());
                messageEntity.setTitle(MessageEnum.MESSAGE_TITLE.getMessage());
            }
            if (flag.equals(MessageEnum.PROJECT_INSERT.getCode())){
                // 動態顯示:新增了xx專案
                messageEntity.setContent(userName+MessageEnum.PROJECT_INSERT.getMessage()+" "+message.getName());
                messageEntity.setSource(MessageSourceEnum.SOURCE_PROJECT.getCode());
                messageEntity.setTitle(MessageEnum.MESSAGE_TITLE.getMessage());
            }
            if (flag.equals(MessageEnum.PROJECT_DELETE.getCode())){
                //動態顯示:洗掉了xx專案
                messageEntity.setContent(userName+MessageEnum.PROJECT_DELETE.getMessage()+" "+message.getName());
                messageEntity.setSource(MessageSourceEnum.SOURCE_PROJECT.getCode());
                messageEntity.setTitle(MessageEnum.MESSAGE_TITLE.getMessage());
            }
            if (flag.equals(MessageEnum.PROJECT_BACK.getCode())) {
                // 動態顯示:還原了xx專案
                messageEntity.setContent(userName+MessageEnum.PROJECT_BACK.getMessage()+" "+message.getName());
                messageEntity.setSource(MessageSourceEnum.SOURCE_PROJECT.getCode());
                messageEntity.setTitle(MessageEnum.MESSAGE_TITLE.getMessage());
            }
    }
 
}


經過測驗,上面的代碼作業的很好,可是上面的代碼是有問題的,上面存在的問題:把不同動態資訊落存的演算法都放在了同一個方法里面,使得該方法很是龐大(現在是只是一個演示,所以看起來還不是很臃腫,假如還有),

下面看一下上面的改進,我們把不同動態的演算法都單獨作為一個方法

 
public class Message {
 
    public void changeMessage(int flag,MessageModel message){
        if (flag.equals(MessageEnum.PROJECT_UPDATE.getCode())){
                // 動態顯示:更新了xx專案
               updateMessage(message)
            }
            if (flag.equals(MessageEnum.PROJECT_INSERT.getCode())){
                // 動態顯示:新增了xx專案
                saveMessage(message)
            }
            if (flag.equals(MessageEnum.PROJECT_DELETE.getCode())){
                //動態顯示:洗掉了xx專案
                deleteMessage(MessageModel message)
            }
            if (flag.equals(MessageEnum.PROJECT_BACK.getCode())) {
                // 動態顯示:還原了xx專案
                backMessage(MessageModel message)
            }
    }
 
    /**
     * 顯示[新增了xx專案]的演算法
     */
    private void saveMessage(MessageModel message) {
        messageEntity.setContent(userName+MessageEnum.PROJECT_INSERT.getMessage()+" "+message.getName());
        messageEntity.setSource(MessageSourceEnum.SOURCE_PROJECT.getCode());
        messageEntity.setTitle(MessageEnum.MESSAGE_TITLE.getMessage());
    }
    
    /**
     * 顯示[更新了xx專案]的演算法
     */
    private void updateMessage(MessageModel message) {
         messageEntity.setContent(userName+MessageEnum.PROJECT_UPDATE.getMessage()+" "+message.getName());
         messageEntity.setSource(MessageSourceEnum.SOURCE_PROJECT.getCode());
         messageEntity.setTitle(MessageEnum.MESSAGE_TITLE.getMessage());
    }
    
    /**
     * 顯示[洗掉了xx專案]的演算法
     */
    private void deleteMessage(MessageModel message) {
         messageEntity.setContent(userName+MessageEnum.PROJECT_DELETE.getMessage()+" "+message.getName());
         messageEntity.setSource(MessageSourceEnum.SOURCE_PROJECT.getCode());
         messageEntity.setTitle(MessageEnum.MESSAGE_TITLE.getMessage());
    }
    
     /**
     * 顯示[還原了xx專案]的演算法
     */
    private void c {
         messageEntity.setContent(userName+MessageEnum.PROJECT_BACK.getMessage()+" "+message.getName());
         messageEntity.setSource(MessageSourceEnum.SOURCE_PROJECT.getCode());
         messageEntity.setTitle(MessageEnum.MESSAGE_TITLE.getMessage());
    }
 
}

上面的代碼比剛開始的時候要好一點,它把每個具體的演算法都單獨抽出來作為一個方法,當某一個具體的演算法有了變動的時候,只需要修改回應的動態演算法就可以了,

但是改進后的代碼還是有問題的,那有什么問題呢?

1.當我們新增一個動態資訊的時候,首先要添加一個該動態資訊的演算法方法,然后再changeMessage方法中再加一個else if的分支,是不是感覺很是麻煩呢?而且這也違反了設計原則之一的開閉原則(open-closed-principle).

開閉原則:

對于擴展是開放的(Open for extension),這意味著模塊的行為是可以擴展的,當應用的需求改變時,我們可以對模塊進行擴展,使其具有滿足那些改變的新行為,也就是說,我們可以改變模塊的功能,
??
??對于修改是關閉的(Closed for modification),對模塊行為進行擴展時,不必改動模塊的源代碼或者二進制代碼,
??
2.我們經常會面臨這樣的情況,如果要修改if else里面的一個分支資訊,那么我們得先找到具體的分支資訊,了解他的邏即,在對代碼進行修改,很是麻煩!!!
那有沒有什么辦法使得我們的動態模塊即可擴展、可維護,又可以方便的回應變化呢?當然有解決方案啦,就是我們下面要講的策略模式,

定義:

策略模式定義了一系列的演算法,并將每一個演算法封裝起來,使每個演算法可以相互替代,使演算法本身和使用演算法的客戶端分割開來,相互獨立,

結構:

1.策略介面角色IStrategy:用來約束一系列具體的策略演算法,策略背景關系角色ConcreteStrategy使用此策略介面來呼叫具體的策略所實作的演算法,
??2.具體策略實作角色ConcreteStrategy:具體的策略實作,即具體的演算法實作,
??3.策略背景關系角色StrategyContext:策略背景關系,負責和具體的策略實作互動,通常策略背景關系物件會持有一個真正的策略實作物件,策略背景關系還可以讓具體的策略實作從其中獲取相關資料,回呼策略背景關系物件的方法,
??
??策略模式代碼的一般通用實作:

策略介面

package strategy.examp01;
 
//策略介面
public interface IStrategy {
    //定義的抽象演算法方法 來約束具體的演算法實作方法
    public void algorithmMethod();
}

具體的策略實作:

package strategy.examp01;
 
// 具體的策略實作
public class ConcreteStrategy implements IStrategy {
    //具體的演算法實作
    @Override
    public void algorithmMethod() {
        System.out.println("this is ConcreteStrategy method...");
    }
}

package strategy.examp01;
 
 // 具體的策略實作2
public class ConcreteStrategy2 implements IStrategy {
     //具體的演算法實作
    @Override
    public void algorithmMethod() {
        System.out.println("this is ConcreteStrategy2 method...");
    }
}

策略背景關系:

package strategy.examp01;
 
/**
 * 策略背景關系
 */
public class StrategyContext {
    //持有一個策略實作的參考
    private IStrategy strategy;
    //使用構造器注入具體的策略類
    public StrategyContext(IStrategy strategy) {
        this.strategy = strategy;
    }
 
    public void contextMethod(){
        //呼叫策略實作的方法
        strategy.algorithmMethod();
    }
}

外部客戶端:

package strategy.examp01;
 
//外部客戶端
public class Client {
    public static void main(String[] args) {
        //1.創建具體測策略實作
        IStrategy strategy = new ConcreteStrategy2();
        //2.在創建策略背景關系的同時,將具體的策略實作物件注入到策略背景關系當中
        StrategyContext ctx = new StrategyContext(strategy);
        //3.呼叫背景關系物件的方法來完成對具體策略實作的回呼
        ctx.contextMethod();
    }
}

策略模式的優點:

  • 策略模式的功能就是通過抽象、封裝來定義一系列的演算法,使得這些演算法可以相互替換,所以為這些演算法定義一個公共的介面,以約束這些演算法的功能實作,如果這些演算法具有公共的功能,可以將介面變為抽象類,將公共功能放到抽象父類里面,

  • 策略模式的一系列演算法是可以相互替換的、是平等的,寫在一起就是if-else組織結構,如果演算法實作里又有條件陳述句,就構成了多重條件陳述句,可以用策略模式,避免這樣的多重條件陳述句,

  • 擴展性更好:在策略模式中擴展策略實作非常的容易,只要新增一個策略實作類,然后在使用策略實作的地方,使用這個新的策略實作就好了,

策略模式的缺點:

  • 客戶端必須了解所有的策略,清楚它們的不同:

如果由客戶端來決定使用何種演算法,那客戶端必須知道所有的策略,清楚各個策略的功能和不同,這樣才能做出正確的選擇,但是這暴露了策略的具體實作,

  • 增加了物件的數量:

由于策略模式將每個具體的演算法都單獨封裝為一個策略類,如果可選的策略有很多的話,那物件的數量也會很多,

  • 只適合偏平的演算法結構:

由于策略模式的各個策略實作是平等的關系(可相互替換),實際上就構成了一個扁平的演算法結構,即一個策略介面下面有多個平等的策略實作(多個策略實作是兄弟關系),并且運行時只能有一個演算法被使用,這就限制了演算法的使用層級,且不能被嵌套,

實操

那么我們對動態模塊采用策略模式的方式進行修改(以動態展示[新增了XX專案]為例)

公共動態策略介面

/**
 * @ClassName MessageStrategy
 * @Description 動態策略介面(此處采用策略模式)
 * @Author HeX
 * @Date 2020/2/26 15:23
 * @Version 1.0
 **/
public interface MessageStrategy {
    /**
     * 新增動態
     * @param messageModels
     * @return
     * @throws Exception
     */
    int batchSaveMessage(List<MessageModel> messageModels) throws Exception;
}

[新增xxx專案]策略實作

/**
 * @ClassName SaveProjectStrategy
 * @Description 保存【新增專案動態】策略
 * @Author HeX
 * @Date 2020/2/26 15:27
 * @Version 1.0
 **/
public class SaveProjectMessageStrategy implements MessageStrategy {
    @Override
    public int batchSaveMessage(MessageModel message) throws Exception {
            // 新增了專案
            messageEntity.setContent(userName + MessageEnum.PROJECT_INSERT.getMessage() + " " + message.getName());
            messageEntity.setSource(MessageSourceEnum.SOURCE_PROJECT.getCode());
            messageEntity.setTitle(MessageEnum.MESSAGE_TITLE.getMessage());
        return 0;
    }
}

動態策略背景關系

/**
 * @ClassName MessageContext
 * @Description 動態背景關系角色
 * @Author HeX
 * @Date 2020/2/26 15:58
 * @Version 1.0
 **/
public class MessageContext {

    /**
     * 持有一個具體的動態策略
     */
    private MessageStrategy messageStrategy;

    /**
     * 注入動態策略
     * @param messageStrategy
     */
    public MessageContext(MessageStrategy messageStrategy){
        this.messageStrategy = messageStrategy;
    }

    /**
     * 回呼具體動態策略的方法
     * @param messageModels
     * @return
     * @throws Exception
     */
    public int saveMessage(List<MessageModel> messageModels) throws Exception {
        return messageStrategy.batchSaveMessage(messageModels);
    }
}

此時,只需要在具體的業務邏輯里呼叫即可,如圖所示:
在這里插入圖片描述

好啦,策略模式就講到這,我們下期見~

轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/227571.html

標籤:其他

上一篇:年輕人你不講武德,自己偷著學習!Spring Security五套「原始碼級」筆記哪里來的?我也要!

下一篇:作業兩年的雙非本渣,剛剛結束百度的Java崗三面(offer還未到手),先把此次的面經分享給大家

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 面試突擊第一季,第二季,第三季

    第一季必考 https://www.bilibili.com/video/BV1FE411y79Y?from=search&seid=15921726601957489746 第二季分布式 https://www.bilibili.com/video/BV13f4y127ee/?spm_id_fro ......

    uj5u.com 2020-09-10 05:35:24 more
  • 第三單元作業總結

    1.前言 這應該是本學期最后一次寫作業總結了吧。總體來說,對作業的節奏也差不多掌握了,作業做起來的效率也更高了。雖然和之前的作業一樣,作業中都要用到新的知識,但是相比之前,更加懂得了如何利用工具以及資料。雖然之間卡過殼,但總體而言,這幾次作業還算完成的比較好。 2.作業程序總結 相比前兩個單元,此單 ......

    uj5u.com 2020-09-10 05:35:41 more
  • 北航OO(2020)第四單元博客作業暨課程總結博客

    北航OO(2020)第四單元博客作業暨課程總結博客 本單元作業的架構設計 在本單元中,由于UML圖具有比較清晰的樹形結構,因此我對其中需要進行查詢操作的元素進行了包裝,在樹的父節點中存盤所有孩子的參考。考慮到性能問題,我采用了快取機制,一次查詢后盡可能快取已經遍歷過的資訊,以減少遍歷次數。 本單元我 ......

    uj5u.com 2020-09-10 05:35:48 more
  • BUAA_OO_第四單元

    一、UML決議器設計 ? 先看下題目:第四單元實作一個基于JDK 8帶有效性檢查的UML(Unified Modeling Language)類圖,順序圖,狀態圖分析器 MyUmlInteraction,實際上我們要建立一個有向圖模型,UML中的物件(元素)可能與同級元素連接,也可與低級元素相連形成 ......

    uj5u.com 2020-09-10 05:35:54 more
  • 6.1邏輯運算子

    邏輯運算子 1. && 短路與 運算式1 && 運算式2 01.運算式1為true并且運算式2也為true 整體回傳為true 02.運算式1為false,將不會執行運算式2 整體回傳為false 03.只要有一個運算式為false 整體回傳為false 2. || 短路或 運算式1 || 運算式2 ......

    uj5u.com 2020-09-10 05:35:56 more
  • BUAAOO 第四單元 & 課程總結

    1. 第四單元:StarUml檔案決議 本單元采用了圖模型決議UML。 UML檔案可以抽象為圖、子圖、邊的邏輯結構。 在實作中,圖的節點包括類、介面、屬性,子圖包括狀態圖、順序圖等。 采用了三次遍歷UML元素的方法建圖,第一遍遍歷建點,第二、三次遍歷設定屬性、連邊,實作圖物件的初始化。這里借鑒了一些 ......

    uj5u.com 2020-09-10 05:36:06 more
  • 談談我對C# 多型的理解

    面向物件三要素:封裝、繼承、多型。 封裝和繼承,這兩個比較好理解,但要理解多型的話,可就稍微有點難度了。今天,我們就來講講多型的理解。 我們應該經常會看到面試題目:請談談對多型的理解。 其實呢,多型非常簡單,就一句話:呼叫同一種方法產生了不同的結果。 具體實作方式有三種。 一、多載 多載很簡單。 p ......

    uj5u.com 2020-09-10 05:36:09 more
  • Python 資料驅動工具:DDT

    背景 python 的unittest 沒有自帶資料驅動功能。 所以如果使用unittest,同時又想使用資料驅動,那么就可以使用DDT來完成。 DDT是 “Data-Driven Tests”的縮寫。 資料:http://ddt.readthedocs.io/en/latest/ 使用方法 dd. ......

    uj5u.com 2020-09-10 05:36:13 more
  • Python里面的xlrd模塊詳解

    那我就一下面積個問題對xlrd模塊進行學習一下: 1.什么是xlrd模塊? 2.為什么使用xlrd模塊? 3.怎樣使用xlrd模塊? 1.什么是xlrd模塊? ?python操作excel主要用到xlrd和xlwt這兩個庫,即xlrd是讀excel,xlwt是寫excel的庫。 今天就先來說一下xl ......

    uj5u.com 2020-09-10 05:36:28 more
  • 當我們創建HashMap時,底層到底做了什么?

    jdk1.7中的底層實作程序(底層基于陣列+鏈表) 在我們new HashMap()時,底層創建了默認長度為16的一維陣列Entry[ ] table。當我們呼叫map.put(key1,value1)方法向HashMap里添加資料的時候: 首先,呼叫key1所在類的hashCode()計算key1 ......

    uj5u.com 2020-09-10 05:36:38 more
最新发布
  • 【中介者設計模式詳解】C/Java/JS/Go/Python/TS不同語言實作

    * 中介者模式是一種行為型設計模式,它可以用來減少類之間的直接依賴關系,
    * 將物件之間的通信封裝到一個中介者物件中,從而使得各個物件之間的關系更加松散。
    * 在中介者模式中,物件之間不再直接相互互動,而是通過中介者來中轉訊息。 ......

    uj5u.com 2023-04-20 08:20:47 more
  • 露天煤礦現場調研和交流案例分享

    他們集團的資訊化公司及研究院在一個礦區正在做智能礦山的統一平臺的 試點,專案投資大概1億,包括了礦山的各方面的內容,顯示得我們這次交流有點多余。他們2年前開始做智能礦山的規劃,有很多煤礦行業專家的加持,他們的描述是非常完美,但是去年底應該上線的平臺,現在還沒有看到影子。他們確實有很多場景需求,但是被... ......

    uj5u.com 2023-04-20 08:20:25 more
  • 《社區人員管理》實戰案例設計&個人案例分享

    設計是一個讓人夢想成真程序,開始編碼、測驗、除錯之前進行需求分析和架構設計,才能保證關鍵方面都做正確 ......

    uj5u.com 2023-04-20 08:20:17 more
  • 軟體架構生態化-多角色交付的探索實踐

    作為一個技術架構師,不僅僅要緊跟行業技術趨勢,還要結合研發團隊現狀及痛點,探索新的交付方案。在日常中,你是否遇到如下問題 “ 業務需求排期長研發是瓶頸;非研發角色感受不到研發技改提效的變化;引入ISV 團隊又擔心質量和安全,培訓周期長“等等,基于此我們探索了一種新的技術體系及交付方案來解決如上問題。 ......

    uj5u.com 2023-04-20 08:20:10 more
  • 【中介者設計模式詳解】C/Java/JS/Go/Python/TS不同語言實作

    * 中介者模式是一種行為型設計模式,它可以用來減少類之間的直接依賴關系,
    * 將物件之間的通信封裝到一個中介者物件中,從而使得各個物件之間的關系更加松散。
    * 在中介者模式中,物件之間不再直接相互互動,而是通過中介者來中轉訊息。 ......

    uj5u.com 2023-04-20 08:19:44 more
  • 露天煤礦現場調研和交流案例分享

    他們集團的資訊化公司及研究院在一個礦區正在做智能礦山的統一平臺的 試點,專案投資大概1億,包括了礦山的各方面的內容,顯示得我們這次交流有點多余。他們2年前開始做智能礦山的規劃,有很多煤礦行業專家的加持,他們的描述是非常完美,但是去年底應該上線的平臺,現在還沒有看到影子。他們確實有很多場景需求,但是被... ......

    uj5u.com 2023-04-20 08:19:07 more
  • 《社區人員管理》實戰案例設計&個人案例分享

    設計是一個讓人夢想成真程序,開始編碼、測驗、除錯之前進行需求分析和架構設計,才能保證關鍵方面都做正確 ......

    uj5u.com 2023-04-20 08:18:57 more
  • 軟體架構生態化-多角色交付的探索實踐

    作為一個技術架構師,不僅僅要緊跟行業技術趨勢,還要結合研發團隊現狀及痛點,探索新的交付方案。在日常中,你是否遇到如下問題 “ 業務需求排期長研發是瓶頸;非研發角色感受不到研發技改提效的變化;引入ISV 團隊又擔心質量和安全,培訓周期長“等等,基于此我們探索了一種新的技術體系及交付方案來解決如上問題。 ......

    uj5u.com 2023-04-20 08:18:49 more
  • 05單件模式

    #經典的單件模式 public class Singleton { private static Singleton uniqueInstance; //一個靜態變數持有Singleton類的唯一實體。 // 其他有用的實體變數寫在這里 //構造器宣告為私有,只有Singleton可以實體化這個類! ......

    uj5u.com 2023-04-19 08:42:51 more
  • 【架構與設計】常見微服務分層架構的區別和落地實踐

    軟體工程的方方面面都遵循一個最基本的道理:沒有銀彈,架構分層模型更是如此,每一種都有各自優缺點,所以請根據不同的業務場景,并遵循簡單、可演進這兩個重要的架構原則選擇合適的架構分層模型即可。 ......

    uj5u.com 2023-04-19 08:42:41 more