設計模式(2) 策略模式

2021-10-06 02:44:43 字數 3873 閱讀 7268

我有乙個夢想,我寫的**,可以像詩一樣優美。我有乙個夢想,我做的設計,能恰到好處,既不過度,也無不足。

前面說了常用的工廠方法模式、簡單工廠、抽象工廠,今天說一下策略模式。

策略模式我的理解其實很像工廠模式,這也是為什麼第二個會寫策略模式的原因。

策略模式

從結構上來講策略模式分為乙個持有具體演算法引用的類(下文為了方便描述,統稱為上下文使用類)和演算法,外部呼叫者通過傳入不同的條件,由上下文使用類生出不同的演算法,根據演算法計算出外部想要的結果,返回給呼叫者。

為什麼要用策略模式

當業務規則在不同時期會有不同的變化,

具體來分析一下

先來梳理一下策略模式中的各結構部分:

上下文使用類,演算法基類(抽象類),各演算法具體實現類(繼承自演算法基類)。

仔細看一下,是不是和工廠模式有些神似。

下面將通過實際**來展示一下,一下**是我專案中寫的乙個有關解析的策略模式使用部分(當然了,肯定不能是專案中直接拿出來)

需求脫離實際情況的任何涉及都是扯淡,先簡要說明一下這部分的需求。

需求:通過對座標檔案的解析,獲取乙份關於台站名稱和其對應的座標位置的map.

專案啟動時,給到的座標檔案只有一種格式(這也是埋下了要使用策略的伏筆),即「台站名稱 — 南北座標 — 東西座標 ---- 高層座標 」,為了後文描述,統稱為「名稱 ---- x座標 ---- y座標 ---- z座標 」,z座標如果沒有則預設為0。

好,有了需求,實現就簡單了,反正確定了只有一種格式。

class txtparser

;

簡單寫一下類的主要結構,其他私有函式以及實現就不寫了,就是解析文字檔案相關。

在專案中需要解析的時候,直接使用txtparser解析獲取qmap即可。

注:position為自定義的結構

struct position

;

專案1.0交給客戶的時候,開始還好好的,後面就反饋座標檔案解析不成功,所有台站座標都是(0, 0, 0)。

這種(0, 0, 0)的座標產生,只能說明檔案解析出錯,當某個台站的座標不正確,取得的字串沒有成功轉化為數字時,軟體將預設座標為(0, 0, 0)。

把日誌發過來一看,果然是嘛,於是讓客戶檢查座標檔案,答覆:每個座標都正確。

於是乎,自己達到客戶使用的座標檔案,一看,好嘛,座標是都沒問題,可是檔案格式都變了好嘛。

新的檔案格式為:

「臺陣名稱 ----- 資料檔案名稱 ---- x ----- y ----- z 」

這不解析失敗才怪。

為什麼會有個資料檔案名稱,涉及專案結構,解釋起來有點麻煩,就不說了,反正知道格式有了變化就行了。

這不需求就來了,再新增一種格式檔案的解析。

先談一下解決思路:

條條大路通羅馬,但是總有一條更適合走。

兩種型別,首先能想到的是在原txtparser類中新增針對這種格式是成員函式,比如:

class txtparser

;

這種方法通過函式過載方式,可以達到我們想要的效果,但是總有一點不舒服,如果需求剛開始就非常明確就是兩種格式,以後也不會改變和增加,那麼開始就設計成這種函式過載方式完全ok。

但是這種需求似乎並不能夠這麼明確的定死,這次突然加入一種格式就是個例子,如果每次座標檔案的格式有所變化,那是不是每次都要更改這個解析類?

答案是:不是(或者最好不是)。

大到整個專案的設計,小到乙個小模組的設計都應該遵循乙個道理:開放–封閉原則。

即當產生變化時,結構或者類對擴充套件開放,對更改關閉。

也就是說當你要增添乙個功能的時候,最好的方式應該是在原有的基礎上去擴充套件,而不應該選擇去改變已經有的部分,因為如果乙個專案或者模組足夠複雜,這意味著你可能不會注意到其他地方的使用情況,也就有可能造成現有系統或者模組的崩潰等問題。

好,現在確定不用這條路子,那換一種路子,重寫乙個解析類行嗎?

class txtparser2

;

可以,完全ok,結合上篇說到的工廠,這裡完全可以套用。

一、客戶端(也就是使用解析類的模組)在不同的時刻自己選擇例項化相應的解析類,進而完成解析等運算。

ps:這裡的解析類就作為產品類,客戶端自己相當於維持了乙個工廠的作用,選擇生產的產品。

注意

這裡就要要求使用者必須明確知道有哪些解析類,並且知道什麼時候使用什麼類,當相似的類變得越來越多的時候,對客戶端的使用壓力會增大。

二、使用工廠方法模式

每乙個工廠對應一種解析類(產品)。

注意

這種方法要做的有:每增加一種解析類,則對應增加乙個工廠類,**量上會增加(對程式設計師來說,這就是原罪),而且使用端使用過程中至少要了解的:1.所有的工廠類以及什麼時候使用什麼工廠,2.至少要知道乙個產品的抽象基類(如果採取所有解析類繼承自同乙個抽象基類的情況),如果不使用抽象基類,那不好意思,使用端還需要知道所有的解析類(產品類),還要知道哪種解析類對應哪種工廠。

光是想到這些,我想大家也不會願意吧。

三、抽象工廠

我覺得這個需求沒有必要硬往上面靠,就不強求貼著說了。

下面直接來說說我的解決方法 --------策略模式(其實是策略模式加簡單工廠的組合)

先上**:

class configfiletext

;

class iparser      //抽象基類,後面的解析類都繼承自此類

;

class txtparser1 : public iparser

;

class txtparser2 : public iparser

;

為了方便了解使用原理,我把其他的實際專案相關部分全部去掉了,然後將其中的單個檔案部分拆開形成兩個解析類來講,現在我們來講一下各部分的關聯以及使用的過程。

txtparser1、 txtparser2都繼承自iparser基類,configfiletext類內部維持了乙個對解析類的引用,即iparser *指標。

使用:客戶端只需要知道configfiletext這個類,通過setfile()將檔案完整名稱傳入configfiletext,然後通過getnameposmap()獲取qmap即可。在setfile()中由configfiletext處理選擇例項化哪個解析類。

整個過程中使用端只需要知道configfiletext類即可,不需要也不必需要知道有哪幾種解析類,只管傳入完整檔名及獲取資料即可。

到了這裡,相信仔細的小夥伴已經看出來不是單純的策略類了吧,單純的策略類,還是需要外部使用端明確使用哪種策略(或者演算法),但是這樣外部使用端就又需要了解哪種情況下使用哪種策略,使用壓力就變大了。

用簡單工廠方法和策略類的結合,好處在於將判斷例項化策略的壓力轉嫁到configfiletext類中,使用端不需要了解內部的實現,當然也有缺點:就是在增加新的策略(這裡指的是解析方式)時,在擴充套件乙個解析類的同時,還需要在configfiletext的內部工廠中增加對應解析類的判斷以及例項化,這樣就又違背了「封閉—開放原則」。

結論:無論哪一種模式都有其自己的優點和缺點,對於選擇哪一種方式,還需要自己在實際情況下去判斷

寫在最後:

本來想把策略模式從其原本的由客戶端判斷使用哪種策略的方式開始寫,但是,碼字是真的累,都沒有自動補全功能(不習慣,哈哈),這些都是分好幾次寫才寫完。

另外:**位址(和本文不相同相同,本文講解了單個檔案的內容,**中考慮了以後可能增加多檔案解析的情況,將涉及具體實現的部分都作了刪除,只保留幾個功能演示函式)。

設計模式 策略模式 2

設計模式,先說設計模式吧,對於設計模式而言,這裡邊把事物具體抽象出來,就剩下什麼了?就剩下 如何用乙個良好的結構儲存資料?然後如何用乙個擴充套件性強,可維護性高的操作,來實現這些資料的操作與控制 好了,感言說完了,接下來就是,聊一聊設計模式中的 策略模式!對於策略模式而言,有乙個比較好的例子,那就是...

2 設計模式 策略模式

定義 它定義了演算法家族,分別封裝起來,讓他們之間可以互相替換,此模式讓演算法的變化,不會直接影響到用演算法的客戶。模式分析 策略模式是一種定義一系列演算法的模式,完成的工作相同,只是由於實現不同,所以以相同的方式呼叫,減少了各種演算法類與使用演算法類之間的耦合。策略模式可以封裝任何型別的規則,實踐...

設計模式2 策略模式

abstract class strategypublic class concretestrategya extends strategy public class concretestrategyb extends strategy public class concretestrategyc ...