掃盲:策略模式,成事兒還需要策略

2021-03-06 nanchen
寫在前面

前面也給大家說了,掃盲系列第一個專題是:設計模式,今天它來啦。設計模式是我們開發的內功,很多同學都知道設計模式很有用,但我們卻總是很難記住它,尤其是對於定義。其實,我們從來都不需要去記住它,但學習是必要的,我們需要把每一個招式化為自己的血肉,在編寫代碼的時候多一種設計手段。

設計模式來源於生活,我們更應該用生活和它類比起來。掃盲系列只會講重點的設計模式,對於部分簡單的設計模式,不會花太多篇幅。

此外,對於設計模式,本身都很相似,很難界定,如果你有自己的想法,一定要勇敢站出來和大家 argue。

好的,就這樣,今天就帶來第一篇設計模式:策略模式。

什麼是策略模式?生活中的策略

策略模式在生活中體現很多。

我們要去旅遊,我們可以選擇不同的出行方式:飛機,火車,大巴,自駕等,這是不同的策略。

雙十一當當網購買滿減活動,滿 100 減 50,滿 200 減 100,滿 400 減 250 等,這也是不同的策略。

抑或是我們在追求女生時,針對不同性格的女孩子採用不同的方式,這還是不同的策略。

程序中的策略

策略模式在程序中的體現依然淋漓盡致。

比如我們的圖片加載,Android 上有 Fresco,Picasso,Glide,Universal-Image-Loader 等,iOS 上有 SDWebImage、AFNetworking、FastImageCache 等。

所以,假設讓你來設計一個圖片加載上層框架,要求可以底層可以使用 A B 兩種加載策略,你會怎麼做呢?

// 加載類A
public class ImageLoadServiceA {
public void loadImage() {
System.out.println("使用 A 加載框架");
}
}
// 加載類B
public class ImageLoadServiceB {
public void loadImage() {
System.out.println("使用 B 加載框架");
}
}

// 使用
public void loadNetImage(boolean useA) {
if(useA){
new ImageLoadServiceA().loadImage();// 使用A加載方式
} else {
new ImageLoadServiceB().loadImage();// 使用B加載方式
}
}

可以看到,上述通過一個 useA 參數判斷是否使用 A 框架,為 true 使用 A,否則使用 B 框架進行加載。

使用簡單工廠模式應對

但假設我們現在需要再支持一個 C 框架的使用,你可能想到了,那就再加一個 boolean 參數 useB 即可,或者直接使用一個 int 參數 loadType,宏定義 0 代表 A 框架,1 代表 B 框架,2 代表 C 框架,這樣如果需要增加方式則更新取值即可。

設計模式不過是我們寫程序的招式,由於之前大家可能還學習過了簡單工廠模式,我們不妨在這裡進行實戰。

// 抽象圖片加載類
public abstract class ImageLoadService {
public abstract void loadImage();
}

// 具體加載類A
public class ImageLoadServiceA extends ImageLoadService {
@Override
public void loadImage() {
System.out.println("使用 A 加載框架");
}
}
//具體加載類B
public class ImageLoadServiceB extends ImageLoadService {
@Override
public void loadImage() {
System.out.println("使用 B 加載框架");
}
}

//具體加載類C
public class ImageLoadServiceC extends ImageLoadService {
@Override
public void loadImage() {
System.out.println("使用 C 加載框架");
}
}

public class ImageLoadFactory {
public static ImageLoadService create(int loadType) {
ImageLoadService loadService = null;
switch (loadType) {
case 0:
loadService = new ImageLoadServiceA();
break;
case 1:
loadService = new ImageLoadServiceB();
break;
case 2:
loadService = new ImageLoadServiceC();
break;
}
return loadService;
}
}

// 使用
public void loadNetImage(int loadType) {
ImageLoadFactory.create(loadType).loadImage();
}

可以看到,我們使用簡單工廠模式後,在處理新增其他加載方式的問題的時候,不會再去影響原有的加載類代碼,如果新增一種加載方式的話,我們只需要新增 ImageLoadXXX 類,實現 loadImage() 加載方法,再修改工廠類 ImageLoadFactory 即可。

相信你也發現了,這個方式只能解決對象的創建問題,我們每次新增方式的時候都會新增一個類,而且需要對工廠類進行代碼修改,顯然是違反了開閉原則。

策略模式

人生處處有策略,上面的不同的加載方式其實就是不同的「策略」。

策略模式是對 算法的封裝,它將每一個算法封裝到具有共同接口的獨立的類中,從而使得它們可以獨立變換。

策略模式的特點策略模式的結構


策略模式做實現

要學習一個設計模式,先要學會臨摹,所以上面的需求,我們可以實現為:

定義抽象策略

public interface ImageLoadStrategy {
void loadImage() ;
}

定義具體的策略

// 具體加載類A
public class ImageLoadStrategyA implements ImageLoadStrategy {
@Override
public void loadImage() {
System.out.println("使用 A 加載框架");
}
}
//具體加載類B
public class ImageLoadStrategyB implements ImageLoadStrategy {
@Override
public void loadImage() {
System.out.println("使用 B 加載框架");
}
}

//具體加載類C
public class ImageLoadStrategyC implements ImageLoadStrategy {
@Override
public void loadImage() {
System.out.println("使用 C 加載框架");
}
}

定義上下文,選擇方式

public class ContextImageLoadStrategy {

private ImageLoadStrategy strategy ;

public ContextImageLoadStrategy(ImageLoadStrategy strategy){
this.strategy = strategy ;
}

public void loadImage(){
strategy.loadImage();
}
}

使用

public void loadImage(ImageLoadStrategy imageLoadStrategy){
ContextImageLoadStrategy contextStrategy = new ContextImageLoadStrategy(imageLoadStrategy);
contextStrategy.loadImage();
}

注意:策略的核心不是如何實現算法,而是如何更優雅的把這些算法組織起來,讓客戶端非常好調用「雖然策略非常多,可以自由切換,但是同一時間客戶端只能調用一個策略,其實也很好理解,你不可能同時既坐飛機,又坐火車」。

策略模式的優點

策略類可以互相替換
由於策略類都實現同一個接口,因此他們能夠互相替換。

耦合度低,方便擴展
增加一個新的策略只需要添加一個具體的策略類即可,基本不需要改變原有的代碼,符合開閉原則。

避免使用多重條件選擇語句(if-else 或者 switch)。

策略模式的缺點

你有想到如何解決「客戶端必須知道所有的策略類」這個缺點麼?

策略模式的應用場景

同一個問題具有不同算法時,即僅僅是具體的實現細節不同時,如各種排序算法等等。

對客戶隱藏具體策略(算法)的實現細節,彼此完全獨立;提高算法的保密性與安全性。

一個類擁有很多行為,而又需要使用 if-else 或者 switch 語句來選擇具體行為時。使用策略模式把這些行為獨立到具體的策略類中,可以避免多重選擇的結構。

源碼中的策略模式

想必大家已經很清楚上面的策略模式了,下面源碼中用到策略模式了嗎?

寫在最後

總的來說,策略模式還算我們項目開發中會使用非常頻繁的模式,你學會了麼?如有疑問,請在評論區留言。

—————END—————

我是南塵,只做比心的公眾號,歡迎關注我。

推薦閱讀:

nanchen,是一個怎樣的公眾號?

歡迎關注南塵的公眾號:nanchen
做不完的開源,寫不完的矯情,只做比心的公眾號,如果你喜歡,你可以選擇分享給大家。如果你有好的文章,歡迎投稿,讓我們一起來分享。          長按上方二維碼關注        做不完的開源,寫不完的矯情        一起來看 nanchen 同學的成長筆記

相關焦點

  • 設計模式——策略模式
    策略模式就是用來封裝算法的,但在實踐中,我們發現可以用它來封裝幾乎任何類型的規則,只要在分析過程中聽到需要在不同時間應用不同的業務規則,就可以考慮使用策略模式處理這種變化的可能性。策略模式和簡單工廠模式的區別:簡單工廠模式:只需要發出命令,由他人去實現。策略模式:不知要發出命令,還得由自己親自去做。3.
  • 策略模式(上)
    找出應用中可能需要變化之處,把它們獨立出來,不要和那些不需要變化的代碼混在一起。這樣的概念很簡單,幾乎是每個設計模式背後的精神所在。所有的模式都提供了一套方法讓「系統中的某部分改變不會影響其它部分」。但工廠模式不是我們本次的重點,關於這一點我會稍後再略作解釋,讓我們繼續完善我們的代碼吧!之前我們說要把鴨子的行為設計成可以動態改變,現在貌似還差點火候。
  • 策略模式
    思考一下:實現某一功能可以有多種算法或策略,我需要根據條件選擇相應的算法或策略來完成該功能。如:排序算法,可以使用冒泡排序、歸併排序、快速排序等。要怎麼實現呢?很多同學想,寫個類,每個方法是一種排序算法,然後再封裝一個方法寫 if...else...
  • Java設計模式之策略模式詳解
    前言在軟體領域中,設計模式作為一種經典的開發實踐常常需要我們去深入的理解,而策略模式作為設計模式的一種,使用頻率也是相對來說比較高的,在Java中,當我們學習TreeSet集合的時候,就採用了經典的策略模式的思想,本文主要講解策略模式。
  • 閱讀策略的教學模式解讀
    這幾年,看到很多推廣原版書閱讀的人在到處宣揚閱讀策略時,應該如何如何等等,在「閱讀策略」這個概念最火的時候,甚至還有很多人把閱讀教學中的工具應用也說成了策略
  • Java策略模式
    在策略模式中,可以在運行時更改類行為或其算法。 這種類型的設計模式屬於行為模式。在策略模式中,創建表示各種策略對象和其行為根據其策略對象而變化的上下文對象。 策略對象更改上下文對象的執行算法。實現實例在這個示例中,將創建一個 Strategy 接口,定義實現策略接口的操作和具體策略類。 上下文類- Context 是使用策略的類。StrategyPatternDemo是一個演示類,將使用上下文- Context 和策略對象來演示上下文行為基於其部署或使用的策略的變化。
  • 策略模式,看這一篇就夠了
    策略模式官方定義為,一個類的行為或其算法可以在運行時更改,讀起來意思很模糊,也很難理解。下面我們就一步一步寫代碼來實現策略模式。無疑就需要再寫一個參數相應類型的方法。那如果我們想要對比一個類嗯,比如貓類,狗類。這裡我是寫了一個compareTo的方法去對某個屬性做了比較,那麼我們sort方法的參數就需要用這個類做參數。那我不同的類,sort方法都要重新去寫一遍嗎?
  • 設計模式之策略模式
    行為型設計模式策略模式一簡介當一個對象有多種行為要執行時,我們可以使用策略模式,讓對象自由選擇執行的行為種類,避免使用if…else if….else if…這種嵌套代碼如果我們使用策略模式,某個行為要修改代碼,我們只要修改對應行為的類,都不用動到舊代碼。後期如果要撤掉某種行為或增加某種行為,都比較方便。二例子假設系統維護裡,會發送命令:分析系統cpu使用情況,分析系統memory使用情況,分析系統io情況。後端系統執行命令後,將結果傳回前端,供界面展示結果,畫趨勢圖。
  • 乾貨,策略模式你不知道的
    百度一搜,策略模式想必各類文章都有,今天講一講你在其他地方看不到的策略模式的思想。代碼誰都會寫,思想不是誰都有的。策略模式上節我們稍微的探討了下SpringSession中包含的設計模式。SpringSession 設計模式分析這節我們應用下SpringSession 所涉及的策略模式。
  • 低價策略、高價策略及價格鎖定策略
    人活著做不了幾件事兒。一件事兒做好了就功德無量。現在每天關注10個搞塔羅的能做到(只關注新浪微博上的),每天讓技術人員更300個穿透系統,她們能做到。穿透系統更多了,她們的技術就會越來越好。永遠的低價系統98/188/398,就這樣吧!
  • 用戶決策的不同模式及營銷策略
    針對不同的產品組和不同的決策類型,我們需要制定合適的營銷策略。偏好策略:在可考慮產品組的重決策模式重決策一般會有多種備選方案和多個判斷維度,因此需要在用戶重點關注的判斷維度上建立自己的強勢地位,並通過營銷觸達將自己的強勢地位讓用戶感知到。給出足夠有說服力的理由讓用戶選擇你,而不是可考慮產品組的其他品牌。2.
  • 去掉臃腫的if else代碼塊(策略設計模式)
    枚舉類CalcTypeEnum增加乘方的枚舉值修改Calculator類,增加一個乘方的方法,然後在calc方法中再增加一個else if 塊該實現的最大的問題是當我們新增一種運算時除了要新增代碼,還需要修改原來的calc代碼,這不太好,我們希望新增運算功能時只需要新增代碼,不要修改原來已有的代碼
  • 教學設計的模式和教學策略的分類
    教學設計過程的模式則是在教學設計的實踐當中逐漸形成的,運用系統方法進行教學開發、設計的理論的簡化形式。教學設計的一般模式是適合於多種設計類型的教學模式,需要找到教學設計的基本組成部分。教學設計者在教學設計實踐的基礎上總結出教學設計過程的基本要素,如圖1-1所示。通過對教學設計模式的基本構成要素的分析,以及教學設計的實踐,我們得出教學設計的一般模式,如圖1-2所示。
  • C語言,去你的策略模式!
    因此對於文章的內容,請大家主要關注、體會設計模式本身,更多地去考慮程序的可擴展性和可維護性。文章本身是希望向C語言愛好者普及設計模式的知識,在所有的程序設計中,本意都是儘可能地簡單易懂。因此拋開設計模式的本意去討論程序的代碼實現優劣,是沒有任何意義的。
  • 設計模式之策略模式(Java實現例子說明)
    設計模式之策略模式小王在和同事正在吹牛時,領導過來了,小王啊,你又在吹牛了?別吹了,幹點正活,下周要去春遊,你給出幾種方案。小王一聽去旅遊,屁顛屁顛地去幹活了。這個其實就是一個設計模式,叫做策略模式。策略模式(Strategy Pattern):定義一組算法,將每個算法封裝起來,並且使他們之間可以互換。策略模式是一個簡單的模式也叫做政策模式。
  • Vue 騷技巧,策略模式實現動態表單驗證
    3. 策略模式的通用實現根據上面的例子提煉一下策略模式,折扣計算方式可以被認為是策略(Strategy),這些策略之間可以相互替代,而具體折扣的計算過程可以被認為是封裝上下文(Context),封裝上下文可以根據需要選擇不同的策略。
  • 【教】教學設計的模式和教學策略的分類
    模式是再現現實的一種理論性的簡化形式。教學設計過程的模式則是在教學設計的實踐當中逐漸形成的,運用系統方法進行教學開發、設計的理論的簡化形式。教學設計的一般模式教學設計的一般模式是適合於多種設計類型的教學模式,需要找到教學設計的基本組成部分。教學設計者在教學設計實踐的基礎上總結出教學設計過程的基本要素,如圖1-1所示。
  • 微信讀書還需要哪些增長策略?
    微信讀書的故事和用戶使用路徑並不複雜,個人作為微信讀書中度使用用戶,從產品經理的角度來分析一下,它都用過哪些增長策略,以及後續又有哪些值得嘗試的增長點。微信讀書月活增長策略總覽增長策略點一、獲客1.1.2 好友組隊拼團模式,五人組隊,成功之後可以隨機得無限卡。拉新同樣有兩個要素:1)規則限制。獎勵的大小和團隊中新人掛鈎,增加拉新機率。2)社交病毒傳播。觀察2018年推出此功能後朋友圈組隊狀態出現的頻率極高。
  • 你有張良計,我有過牆梯之策略模式
    0x01:策略模式簡介 策略模式指對象有某個行為,但是在不同的場景中,該行為有不同的實現算法。比如每個人都要交個人所得稅,但是根據個人的收入情況,個人所得稅的計算算法是有不同的策略的。
  • 股票策略產品冰火兩重天,有私募欲滿倉運作,也有策略成賺錢贏家
    01近八成股票產品虧損,管理期貨成「熊市」贏家在市場持續下跌低迷之下,與市場緊密相關的股票私募自然無法獨善其身。從私募排排網數據中心來看,從年後2月3日開始以來截止到3月25日,納入統計8515隻股票策略產品中,平均收益錄得-4.13%,最高收益70.47%,而最大的虧損也達到了60.56%,僅僅只有20.90%的產品錄得正收益,也就是說,鼠年以來有將近八成的股票策略產品出現了虧損。