目錄
定義
類圖
角色? ? ? ??
角色詳解
Strategy(抽象策略類)?
Context(環境類 / 上下文類)?
ConcreteStrategy(具體策略類)?
優缺點
優點?
缺點?
使用場景
類行為差異場景?
動態算法選擇場景?
避免復雜條件語句場景?
保密性與安全性場景?
定義
????????策略模式作為一種行為型設計模式,核心在于將對象的行為與對象本身分離開來。它把一系列相關的行為定義為一個行為接口,然后通過不同的具體類來實現這些行為。這種設計方式使得行為可以獨立于使用它們的對象進行變化,極大地增強了系統的靈活性和可擴展性。?
????????簡單來說,策略模式就像是為你的軟件系統準備了一個 “行為工具箱”,里面裝滿了各種不同的行為工具。當你的對象需要執行某種行為時,它可以從這個工具箱中挑選合適的工具,而無需在自身內部固化特定的行為邏輯。例如,在一個電商系統中,對于商品的促銷活動,有打折、滿減、贈品等多種策略。通過策略模式,我們可以將這些促銷策略分別定義為不同的類,每個類實現促銷行為的接口。這樣,在不同的促銷場景下,只需選擇相應的策略類,商品就能以不同的促銷方式進行銷售,而無需頻繁修改商品類的代碼。?
????????從本質上講,策略模式的最大特點就是行為的變化性和可替代性。它允許在運行時動態地選擇和切換行為,就如同你在玩游戲時,可以根據不同的游戲場景和對手特點,靈活地選擇不同的游戲策略一樣。每個具體的行為實現就像是一個獨立的策略,它們之間可以相互替換,以適應不同的業務需求和變化。在編程世界中,這種模式使得算法能夠獨立于使用它的用戶(即對象)而變化,為軟件系統注入了強大的生命力。
類圖
角色? ? ? ??
????????策略模式的類圖清晰地展示了其核心組成部分以及它們之間的關系,主要涉及三個關鍵角色:?
-
Strategy(抽象策略類):這是一個接口或抽象類,它定義了一系列算法標識,也就是若干個抽象方法。這些抽象方法代表了不同策略所共有的行為特征,具體的策略實現類必須實現這些方法。例如,在一個圖形繪制系統中,抽象策略類可能定義了一個 “drawShape” 的抽象方法,用于繪制不同形狀的圖形。而具體的圓形繪制策略類、矩形繪制策略類等都需要實現這個 “drawShape” 方法,以提供各自獨特的繪制邏輯。抽象策略類的存在,就像是為所有具體策略類制定了一個統一的規范,確保它們在行為上具有一致性和可替代性。?
-
Context(環境類 / 上下文類):環境類依賴于抽象策略類,它包含一個用策略接口聲明的變量。這個變量就像是一個 “插座”,可以插入不同的具體策略類 “插頭”。環境類提供一個方法,這個方法持有一個策略類的引用,并最終供客戶端調用。在調用時,該方法會委托策略變量調用具體策略所實現的策略接口中的方法。例如,在一個旅行規劃系統中,環境類可以是 “TravelPlanner”,它有一個屬性是 “TravelStrategy” 類型,用于存儲不同的旅行策略(如飛機旅行策略、火車旅行策略等)。“TravelPlanner” 類還提供一個 “planTravel” 方法,當客戶端調用這個方法時,它會根據當前設置的 “TravelStrategy” 對象,調用相應策略的旅行規劃方法,如飛機旅行策略的 “planByAir” 方法或火車旅行策略的 “planByTrain” 方法。環境類在策略模式中起到了橋梁的作用,它將客戶端的請求與具體的策略實現連接起來,使得客戶端無需關心具體策略的細節,只需與環境類進行交互即可。?
-
ConcreteStrategy(具體策略類):具體策略類是實現抽象策略接口的類,它們針對不同的具體情況,實現了策略接口所定義的抽象方法,給出了算法標識的具體實現。每個具體策略類就像是一把獨特的 “鑰匙”,對應著解決特定問題的特定算法或行為。例如,在一個排序算法的應用場景中,可能有 “BubbleSortStrategy”(冒泡排序策略類)和 “QuickSortStrategy”(快速排序策略類)等具體策略類。“BubbleSortStrategy” 類實現了抽象策略接口中定義的 “sort” 方法,使用冒泡排序算法對數據進行排序;“QuickSortStrategy” 類同樣實現了 “sort” 方法,但采用的是快速排序算法。通過這種方式,不同的具體策略類可以根據實際需求,靈活地替換使用,以達到最佳的排序效果。
角色詳解
Strategy(抽象策略類)?
-
行為抽象:抽象策略類的首要職責是對一系列相關行為進行抽象。它通過定義抽象方法,將不同具體策略類的共同行為特征提取出來,形成一個統一的行為接口。這個接口就像是一個藍圖,為具體策略類的實現提供了指導和規范。例如,在一個支付系統中,抽象策略類 “PaymentStrategy” 可以定義一個 “processPayment” 的抽象方法,用于處理支付行為。無論是信用卡支付策略、支付寶支付策略還是微信支付策略,都需要實現這個 “processPayment” 方法,以完成各自特定的支付流程。通過這種行為抽象,不同的支付策略在對外表現上具有了一致性,都遵循 “PaymentStrategy” 接口所定義的行為規范,使得它們可以在相同的環境中被靈活使用。?
-
代碼復用:當多個具體策略類中存在一些共同的代碼邏輯時,抽象策略類可以將這部分公共代碼提取出來,放在自身的實現中。這樣,具體策略類只需繼承抽象策略類,并專注于實現各自特有的行為邏輯,避免了代碼的重復編寫。例如,在一個圖像處理系統中,抽象策略類 “ImageProcessingStrategy” 可能定義了一些通用的圖像預處理方法,如調整圖像大小、轉換圖像格式等。具體的圖像模糊處理策略類、圖像銳化處理策略類等都繼承自 “ImageProcessingStrategy”,它們可以復用抽象策略類中的預處理方法,同時實現自己獨特的圖像特效處理邏輯。這種代碼復用機制不僅提高了開發效率,還增強了代碼的可維護性,因為當公共代碼需要修改時,只需在抽象策略類中進行一次修改,所有繼承它的具體策略類都會自動應用這些修改。?
-
擴展性支持:抽象策略類為系統的擴展性提供了有力支持。當有新的行為需求出現時,只需創建一個新的具體策略類,實現抽象策略類定義的接口即可。無需對現有的代碼進行大規模修改,就能輕松地將新的策略集成到系統中。例如,在一個游戲角色的技能系統中,如果需要添加一種新的技能策略,如 “FreezeSkillStrategy”(冰凍技能策略),只需要創建一個實現 “SkillStrategy” 抽象策略接口的 “FreezeSkillStrategy” 類,并實現接口中的 “executeSkill” 方法,定義冰凍技能的具體執行邏輯。然后,在游戲運行時,就可以根據需要動態地選擇使用這個新的技能策略,而不會影響到其他已有的技能策略和游戲系統的整體架構。?
Context(環境類 / 上下文類)?
-
策略引用管理:環境類負責持有一個抽象策略類的引用,這個引用就像是一個 “容器”,可以容納不同的具體策略對象。通過這種引用管理方式,環境類可以在運行時動態地切換所使用的策略。例如,在一個物流配送系統中,環境類 “DeliveryContext” 有一個 “DeliveryStrategy” 類型的屬性,用于存儲不同的配送策略(如快遞配送策略、同城配送策略等)。在系統初始化時,可以根據用戶的選擇或系統的配置,將相應的具體配送策略對象賦值給這個屬性。當需要執行配送任務時,“DeliveryContext” 就可以通過這個引用調用具體配送策略的方法,實現不同方式的配送服務。這種策略引用管理機制使得系統能夠根據實際情況靈活地選擇和應用不同的策略,提高了系統的適應性和靈活性。?
-
客戶端交互接口:環境類為客戶端提供了一個統一的交互接口,客戶端通過調用環境類的方法來觸發相應的策略行為,而無需了解具體策略的實現細節。這樣,客戶端與具體策略類之間實現了松耦合,降低了客戶端代碼與策略實現代碼之間的依賴關系。例如,在一個音樂播放系統中,環境類 “MusicPlayerContext” 提供了一個 “playMusic” 方法,客戶端只需調用這個方法,而無需關心音樂播放是采用在線播放策略還是本地播放策略。“MusicPlayerContext” 會根據當前設置的 “MusicPlayStrategy” 對象,調用相應策略的播放方法,實現音樂的播放功能。這種設計方式使得客戶端代碼更加簡潔、易讀,同時也方便了系統的維護和擴展,因為當需要更換音樂播放策略時,只需在 “MusicPlayerContext” 中修改所引用的策略對象,而無需修改客戶端代碼。?
-
策略執行協調:環境類在策略執行過程中起到了協調的作用。它不僅負責將客戶端的請求傳遞給具體策略類,還可以在策略執行前后進行一些額外的處理,如日志記錄、權限驗證等。例如,在一個訂單處理系統中,環境類 “OrderProcessingContext” 在調用具體的訂單處理策略(如普通訂單處理策略、加急訂單處理策略)的 “processOrder” 方法之前,可以先記錄訂單處理的開始時間和相關信息;在策略執行結束后,可以記錄訂單處理的結果和結束時間,并根據處理結果進行相應的后續操作,如發送訂單處理成功或失敗的通知。通過這種策略執行協調機制,環境類可以對整個策略執行過程進行有效的管理和控制,確保系統的運行符合業務需求和規范。?
ConcreteStrategy(具體策略類)?
-
算法實現:具體策略類的核心任務是實現抽象策略類定義的抽象方法,提供具體的算法實現。每個具體策略類針對特定的業務場景或問題,采用不同的算法或邏輯來完成相應的行為。例如,在一個數據加密系統中,“AESEncryptionStrategy” 類實現了抽象策略類 “EncryptionStrategy” 定義的 “encryptData” 方法,使用 AES 加密算法對數據進行加密;而 “RSAEncryptionStrategy” 類同樣實現了 “encryptData” 方法,但采用的是 RSA 加密算法。這些具體策略類通過實現各自獨特的加密算法,為系統提供了多種數據加密選擇,用戶可以根據實際需求和安全要求選擇合適的加密策略。?
-
行為定制:具體策略類可以根據自身的特點和需求,對行為進行定制化處理。它們可以在實現抽象方法的基礎上,添加額外的邏輯和功能,以滿足特定場景下的業務需求。例如,在一個電商平臺的優惠券使用策略中,“PercentageDiscountCouponStrategy” 類實現了抽象策略類 “CouponStrategy” 定義的 “applyCoupon” 方法,用于計算使用百分比折扣優惠券后的商品價格。在這個方法中,除了基本的價格計算邏輯外,還可以添加一些定制化的邏輯,如判斷優惠券是否過期、是否滿足使用條件等。通過這種行為定制機制,具體策略類能夠更加靈活地適應不同的業務場景和變化,為系統提供更加豐富和個性化的功能。?
-
可替換性:具體策略類之間具有可替換性,這是策略模式的重要特性之一。由于它們都實現了相同的抽象策略接口,所以在運行時可以根據需要輕松地將一個具體策略類替換為另一個具體策略類,而不會影響到系統的其他部分。例如,在一個圖形渲染系統中,起初使用 “OpenGLRenderingStrategy” 類來實現圖形渲染功能,但隨著業務發展和技術升級,需要切換到性能更好的 “VulkanRenderingStrategy” 類。由于這兩個類都實現了 “RenderingStrategy” 抽象策略接口,所以只需在環境類中修改所引用的策略對象,將 “OpenGLRenderingStrategy” 替換為 “VulkanRenderingStrategy”,系統就可以無縫地切換到新的渲染策略,而無需對其他模塊的代碼進行大規模修改。這種可替換性使得系統能夠快速適應不同的需求和變化,提高了系統的可維護性和可擴展性。
優缺點
優點?
-
完美支持開閉原則:開閉原則是軟件設計中的重要原則之一,它要求軟件系統對擴展開放,對修改關閉。策略模式為開閉原則提供了近乎完美的支持。當有新的行為或算法需求出現時,我們只需創建一個新的具體策略類,實現抽象策略接口,然后在環境類中進行簡單配置,即可將新的策略集成到系統中,而無需修改現有系統的核心代碼。例如,在一個在線教育平臺的課程推薦系統中,起初使用基于用戶歷史瀏覽記錄的推薦策略,但隨著業務發展,需要增加基于用戶興趣標簽的推薦策略。通過策略模式,我們可以創建一個新的 “InterestBasedRecommendationStrategy” 類,實現 “RecommendationStrategy” 抽象策略接口,然后在課程推薦環境類中添加對這個新策略的支持。這樣,系統在不修改現有推薦策略代碼的基礎上,成功實現了新推薦策略的擴展,有效降低了系統的維護成本和風險。?
-
管理相關算法族:策略模式提供了一種有效的方式來管理一組相關的算法。通過將不同的算法封裝到各自的具體策略類中,并通過抽象策略類進行統一管理,我們可以清晰地組織和維護這些算法。例如,在一個數據處理系統中,有多種數據排序算法(冒泡排序、快速排序、歸并排序等)和數據搜索算法(順序搜索、二分搜索等)。通過策略模式,我們可以將這些排序算法和搜索算法分別封裝到不同的具體策略類中,如 “BubbleSortStrategy”“QuickSortStrategy”“SequentialSearchStrategy”“BinarySearchStrategy” 等。這些具體策略類都繼承自相應的抽象策略類(如 “SortingStrategy”“SearchingStrategy”),形成了一個算法族的層次結構。這種組織方式使得算法的管理更加方便,易于理解和維護,同時也方便了算法的擴展和替換。?
-
替代繼承關系:在傳統的面向對象編程中,當一個類需要有多種不同的行為時,可能會通過繼承來實現,即創建多個子類,每個子類實現不同的行為。然而,這種方式會導致類的數量急劇增加,代碼的復雜度和維護成本也隨之上升,并且在運行時難以動態地改變對象的行為。策略模式提供了一種更靈活的替代方案,它通過將行為封裝到獨立的策略類中,使得對象可以在運行時動態地選擇和切換行為,而無需通過繼承來實現。例如,在一個游戲角色類中,如果使用繼承來實現不同的攻擊行為,可能需要創建 “MeleeAttackCharacter”(近戰攻擊角色類)、“RangedAttackCharacter”(遠程攻擊角色類)等多個子類。而通過策略模式,我們可以創建 “MeleeAttackStrategy” 和 “RangedAttackStrategy” 等具體策略類,游戲角色類只需持有一個 “AttackStrategy” 抽象策略類的引用,在運行時根據實際情況選擇不同的攻擊策略,從而實現不同的攻擊行為。這樣,不僅減少了類的數量,降低了代碼復雜度,還提高了系統的靈活性和可擴展性。?
-
避免多重條件轉移語句:在沒有使用策略模式的情況下,當一個對象需要根據不同的條件執行不同的行為時,往往會使用多重條件轉移語句(如 if-else 或 switch 語句)。然而,隨著條件和行為的增加,這些條件轉移語句會變得冗長、復雜,難以閱讀和維護。策略模式通過將不同的行為封裝到具體策略類中,使得條件判斷和行為執行的邏輯分離,從而避免了使用多重條件轉移語句。例如,在一個訂單處理系統中,如果不使用策略模式,可能會在訂單處理方法中使用大量的 if-else 語句來判斷訂單類型(普通訂單、加急訂單、團購訂單等),并根據不同的訂單類型執行不同的處理邏輯。而使用策略模式后,我們可以創建 “NormalOrderStrategy”“UrgentOrderStrategy”“GroupBuyOrderStrategy” 等具體策略類,訂單處理環境類只需根據訂單類型選擇相應的策略類來執行訂單處理邏輯,無需在代碼中編寫復雜的條件判斷語句。這樣,代碼結構更加清晰,可讀性和可維護性大大提高。?
缺點?
-
客戶端知曉策略類:在策略模式中,客戶端必須了解所有可用的策略類,并自行決定使用哪一個策略類。這就要求客戶端對系統中的各種策略有一定的了解,以便能夠根據實際需求做出正確的選擇。然而,在一些復雜的系統中,策略類的數量可能較多,而且策略的實現細節也可能較為復雜,這增加了客戶端使用的難度。例如,在一個金融投資系統中,有多種投資策略(如價值投資策略、成長投資策略、量化投資策略等),每個策略都有其獨特的算法和風險特點。客戶端在選擇投資策略時,需要對這些策略有深入的了解,才能做出合適的決策。如果客戶端對策略不熟悉,可能會選擇錯誤的策略,導致投資失敗。為了解決這個問題,可以在系統中提供一些輔助工具或文檔,幫助客戶端更好地了解和選擇策略,或者在環境類中提供一些默認的策略選擇邏輯,降低客戶端的使用難度。?
-
策略類數量眾多:由于策略模式將每個具體的行為都封裝成一個獨立的策略類,當系統中的行為種類較多時,會導致策略類的數量急劇增加。這不僅增加了系統的復雜性和維護成本,還可能會使代碼的結構變得混亂。例如,在一個電商平臺的促銷活動系統中,可能有打折、滿減、贈品、限時搶購、團購等多種促銷策略,每種促銷策略都需要一個具體的策略類來實現。隨著業務的發展和促銷活動的不斷創新,可能還會有更多的促銷策略需要添加,這將導致策略類的數量不斷增加?
使用場景
類行為差異場景?
????????當系統中存在眾多類,其差異僅體現在行為方面時,策略模式的優勢便得以凸顯。以游戲開發為例,游戲中有戰士、法師、刺客等多種角色類。戰士擅長近身物理攻擊,法師專注遠程法術輸出,刺客則精于潛行暗殺。這些角色類的核心區別就在于戰斗行為的不同。運用策略模式,我們可以將攻擊行為抽象出來,創建如近戰攻擊策略類、遠程法術攻擊策略類、潛行攻擊策略類等。游戲角色類通過持有攻擊策略接口的引用,在運行時動態選擇相應策略。比如戰士角色在初始化時可選擇近戰攻擊策略,在戰斗中能根據局勢靈活切換,若遇到遠程敵人,可臨時切換為遠程攻擊策略(假設游戲設計允許),從而極大地增強了角色行為的靈活性與可擴展性。?
????????再比如電商平臺中的不同商品類,普通商品、限時折扣商品、團購商品,它們的銷售行為有所不同。普通商品正常售賣,限時折扣商品在特定時間段以折扣價銷售,團購商品需達到一定購買人數才生效。通過策略模式,分別創建普通銷售策略類、限時折扣銷售策略類、團購銷售策略類,商品類通過關聯相應策略,能輕松實現不同銷售行為,并且在促銷活動調整時,方便地切換銷售策略。?
動態算法選擇場景?
????????對于需要動態在幾種算法中抉擇的系統,策略模式堪稱絕佳之選。在數據處理領域,以排序算法為例,常見的有冒泡排序、快速排序、歸并排序等。不同場景對排序算法的性能要求各異,小規模數據可能適合冒泡排序,因其實現簡單;而大規模數據則更適合快速排序或歸并排序以提升效率。通過策略模式,我們將每種排序算法封裝成一個具體策略類,如冒泡排序策略類、快速排序策略類、歸并排序策略類,它們都實現統一的排序策略接口。在數據處理模塊中,根據數據規模、數據特點等因素,動態選擇合適的排序策略。例如,當處理 100 條以內的用戶信息排序時,可選用冒泡排序策略;處理成千上萬條交易數據排序時,則切換為快速排序策略,確保系統在不同情況下都能高效運行。?
????????在圖形渲染系統中,也存在類似情況。渲染 2D 圖形和 3D 圖形需要不同的渲染算法,2D 圖形渲染可能采用簡單的光柵化算法,3D 圖形渲染則需更復雜的光線追蹤算法等。通過策略模式,創建 2D 渲染策略類和 3D 渲染策略類,渲染引擎類根據要渲染的圖形類型,動態調用相應的渲染策略,實現高效且靈活的圖形渲染。?
避免復雜條件語句場景?
????????若一個對象存在大量行為,若不采用合適模式,多重條件選擇語句將不可避免,導致代碼冗長且難以維護。以電商系統的訂單處理模塊為例,訂單有普通訂單、加急訂單、團購訂單、退貨訂單等多種類型,每種訂單的處理流程和規則大相徑庭。傳統做法可能是在訂單處理方法中使用大量 if - else 或 switch 語句判斷訂單類型并執行相應處理邏輯,隨著訂單類型增多,代碼會變得異常復雜。運用策略模式,我們創建普通訂單處理策略類、加急訂單處理策略類、團購訂單處理策略類、退貨訂單處理策略類等,訂單處理類通過持有訂單處理策略接口的引用,根據訂單實際類型調用對應的策略類方法進行處理。如此一來,代碼結構清晰,新增訂單類型時只需添加對應的策略類,無需大幅修改原有代碼,維護成本大幅降低。?
????????在物流配送系統中,配送訂單也有多種類型,如同城配送訂單、跨城配送訂單、國際配送訂單,每種訂單的配送流程、費用計算、運輸方式都不同。如果不使用策略模式,配送處理代碼將充滿復雜的條件判斷。采用策略模式后,分別構建同城配送策略類、跨城配送策略類、國際配送策略類,配送系統根據訂單類型調用相應策略,讓代碼簡潔明了且易于擴展。?
保密性與安全性場景?
????????在保密性與安全性要求較高的場景下,策略模式同樣發揮著重要作用。在金融加密領域,數據加密算法復雜且涉及敏感信息。例如有 AES 加密算法、RSA 加密算法等。通過策略模式,將這些加密算法分別封裝在 AES 加密策略類、RSA 加密策略類中,客戶端只需與加密策略接口交互,無需知曉復雜的算法細節與相關數據結構。在數據傳輸或存儲前,根據安全級別等要求選擇合適的加密策略。如普通用戶數據可選用 AES 加密策略,涉及大額資金交易的數據則采用安全性更高的 RSA 加密策略,既保證了算法的保密性與安全性,又提升了系統對不同安全需求的適應性。?
????????在企業級系統中,訪問權限控制也可應用策略模式。不同級別的用戶(如普通員工、部門經理、系統管理員)對系統資源有不同的訪問權限。將權限驗證算法封裝在相應的策略類中,如普通員工權限策略類、部門經理權限策略類、系統管理員權限策略類。系統在用戶登錄訪問資源時,根據用戶角色調用對應的權限策略,確保敏感信息的安全訪問,同時隱藏了復雜的權限驗證邏輯。?