設計模式(一):“穿越火線”中的“策略模式”(Strategy Pattern)

来源:http://www.cnblogs.com/ludashi/archive/2016/04/08/5302269.html
-Advertisement-
Play Games

在前段時間呢陸陸續續的更新了一系列關於重構的文章。在重構我們既有的代碼時,往往會用到設計模式。在之前重構系列的博客中,我們在重構時用到了“工廠模式”、“策略模式”、“狀態模式”等。當然在重構時,有的地方沒有點明使用的是那種設計模式。從今天開始,我們就圍繞著設計模式這個主題來討論一下我們常用的設計模式 ...


在前段時間呢陸陸續續的更新了一系列關於重構的文章。在重構我們既有的代碼時,往往會用到設計模式。在之前重構系列的博客中,我們在重構時用到了“工廠模式”、“策略模式”、“狀態模式”等。當然在重構時,有的地方沒有點明使用的是那種設計模式。從今天開始,我們就圍繞著設計模式這個主題來討論一下我們常用的設計模式,當然“GoF”的23種設計模式不會全部涉及到,會介紹一些常見的設計模式。在接下來我們要分享的設計模式這個系列博客中,還是以Swift語言為主來實現每種設計模式的Demo。並且仍然會在GitHub上進行Demo的分享,希望與大家相互交流,相互學習,有不足之處還望批評指正。

今天博客的主要思路是先圍繞著“穿越火線”中的角色與武器的關係,通過策略模式來設計實現這種關係,整體的來整體感受一下“策略模式”的優點。然後再參考《Head First Design Patterns》這本書中的鴨子的示例,來一步步使用Swift來實現策略模式的案例。當然我們只是參考《Head First Design Patterns》中的示例,本篇博客中的示例與其中的示例還是有所區別的。大部分設計模式的案例都是使用Java實現的,我們依然會使用Swift來實現。還是那句話,設計模式是針對面向對象編程語言的,而不是針對某一種編程語言,Swift是面向對象的語言,所以設計模式用於Swift編程中是沒有問題的。廢話少說,進入今天博客的主題。

 

一、穿越火線中的“策略模式”(Strategy Pattern)

當然,這個示例是我YY出來的示例,不是“穿越火線”這個游戲的設計方案呢。說到"穿越火線"如果你沒有玩過,那應該聽過吧,就是“CrossFire”。我平時不怎麼玩游戲,穿越火線之前體驗過,不過只有被爆頭的份兒。聽說那些游戲玩家現在不怎麼玩兒“CF”啦,改玩兒Dota,LOL啦,真的是這樣嗎?我個人對於游戲而言是外行了,不過玩個超級瑪麗、魂鬥羅、植物大戰僵屍、節奏大師還是可以的(壞笑)。

言歸正傳,今天我們就模擬穿越火線中角色和武器的關係,使用“策略模式”來實現。首先我們先分析一下這個場景,穿越火線中角色分為不同的等級,也就是“軍銜”了,簡單的說幾個吧,由高到底對應著“軍師旅團營連排小工兵”,上面的是組織,軍銜莫過於各種級計程車官,少中上尉,少中上校,少中上將(應該對吧,本人不太專業呢,不過用於咱們要實現的例子是夠了)。我雖然不怎麼會打CF,可是我會玩軍棋呢。

我是不是刷知乎刷多了,不能在這兒“一本正經的胡說八道”了。言歸正傳,不同的角色所配備的武器裝備也不同,等級越高所使用的武器裝備也就越厲害。我們如何使用面向對象來表達這種角色與武器之間的關係呢?我們先看一下下方的類“類圖”。

      

上面是一個簡化的類“類圖”,上面這種形式可以表達我們之前的那種場景。“軍人”是一個父類,其他具體等級的軍官都繼承自“SuperClass”。那麼問題來了,在上面那種模式下,如果只有“少尉”和“中尉”配備某種武器,其他軍官不配備,我們就要在“少尉”和中尉的類中分別添加要實現的武器,那麼這樣會產生冗餘的代碼。還有個問題是上面的設計形式不利於擴展,比如“少尉”也要配備狙擊步槍,豈不是得從“中尉”中的狙擊步槍的方法複製到“少尉”中。這樣也會產生重覆代碼的。那麼我們該怎樣去解決這個問題呢?

有童鞋說了,在Swift中的Protocol(協議,也就是Java中的介面)可以提供預設的實現。也就是聲明一個protocol,然後通過extension來為協議添加預設實現,只要是類遵循該協議,那麼這個類就擁有了這個預設實現(當然,Java中的介面是不能通過後期的延展來為其添加預設實現的)。如果在Swift中使用介面的預設實現的話,如果要對上述軍官擴充裝備的話,設計中的類“類圖”(不是類圖,但與類圖相似)實現如下所示:

       

上面這種設計模式雖然不會產生重覆的代碼,但是如果給“軍官”添加的武器過多的話,那麼會導致相應的類中實現的介面過多,這並不是我們想要的。下方將會給出一個良好的解決方案,也就是使用策略模式。

 

二、使用“策略模式”(Strategy Pattern)對上述關係進行設計

“策略模式”的定義大概是:策略模式,將不同的策略(演算法)進行封裝,讓他們之間可以相互的替換,此模式讓策略的變化獨立於使用策略的用戶。在設計模式中有不同的設計原則,其中有一條就是“找出程式中可能需要變化的地方,並且把它嗎獨立出來,不要和不變的代碼混在一起”。根據這條設計原則,然後結合著上述示例不難分析出來,在上述示例中,使用軍官使用的不同武器是可以變化的,使用不同的武器正是採取不同的策略呢。

所以經過上述討論,我們可以使用“策略模式”來重新設計上面的結構。簡單的說就是把變化的“武器”部分進行提取,然後在軍官中進行使用,不同的軍官可以採取不同的策略,並且可以隨時替換。下麵是我們使用“策略模式”重新設計後的關係,具體請看下圖。

   

在上面的類“類圖”中我們對可變的“武器策略進行了提取”。我們使用了WeaponBehavior協議來規定武器的策略,使得不同的武器對外有統一的介面,在此就是使用武器,也就是開火。不同的武器使用不同的的“開火策略”,但是對外的介面都是一樣的。設計原則中有一條是“面向介面編程,而不是面向實現編程”。這裡所指的介面可以是協議,可以是抽象類,也可以是超類,其實就是利用面向對象的“多態”特性。上面的紅框中實現的就是所有不同的策略。

而綠框中是我們的用戶,也就是軍官的定義,是我們不變的部分。在軍官中也有一個基類,在基類中定義了軍官的共性,其中依賴於“武器策略”的介面。在軍官超類中使用“武器策略”的協議聲明瞭一個對象,該對象就是該軍官所採取的武器策略。在軍官的超類中可以通過setWeapon()方法採取不同的策略,其中fire()方法就是使用該“武器策略”進行開火。在具體的軍官中的changeXXX()方法就是調用setWeapon()方法進行策略切換的方法。具體內容請看下方的具體實現。

 

三、上述“策略模式”(Strategy Pattern)的具體實現

上面給出了“武器策略模式”的個個部分之間的關係,並給出了相應的解釋。如果對此你感覺到抽象的話,那麼我們接下來就用相應的Swift代碼去實現上述示例。也就是將上面的理論部分進行具體實現,當然在此我們用的是Swift語言,但是,你完全可以使用其他的面向對象編程語言。下麵就是我們具體的代碼實現。

下方就是我們對“武器策略”的實現,紅框中對應的就是上面圖中的WeaponBehavior(協議)介面,下方綠框中就是不同武器的策略,每個武器策略都遵循了WeaponBehavior協議。並且實現了相應的useWeapon()方法。

    

對“武器策略”模塊實現完畢後,接下來我們就得實現軍官模塊了。也是根據上面我們所畫的“模式結構圖”來實現我們的“軍官模塊”,下方Character就是所有軍官的基類,其中預設的武器策略weapon就是手槍(PistolBehavior),其中有設置策略和改變策略的方法,並且還有使用策略的方法(fire())。下方的紅框就是實現的不同的軍官了,不同的軍官可以有不同的切換策略的方法。具體如下所示:

   

上面就是我們全部實現的代碼,下方是我們的測試用例和輸出結果。下方我們創建了一個“中尉”軍官----lieutenant,軍官預設的是開的手槍。但是可以調用相應的changeXXX()方法來切換武器策略。開手槍時,發現火力不行,然後就調用changeHK()方法切換到HK48步槍。這種關係使用“策略模式”就比較靈活,並且便於擴展。比如中尉現在也要配備大狙,因為現在已經有大狙這個武器策略了,所以我們現在只需在中尉中添加相應的change方法,傳入大狙的武器策略即可,具體的就不在演示了。

   

 

本來想著在結合著《Head First Design Patterns》這本書中的鴨子示例在聊一下“策略模式”呢,由於篇幅有限,今天的博客到這兒吧。對於“策略模式”上面是一個完整的示例。

上述代碼gitHub分享地址為:https://github.com/lizelu/DesignPatterns-Swift


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 看起來不錯的一套一元雲購CMS源碼,源碼包裡面帶了安卓和ios手機客戶端,手機客戶端需要自己反編譯。 這裡不做功能和其它更多的介紹,可以自己下載後慢慢測試瞭解。 下麵演示圖為親測截圖<ignore_js_op> <ignore_js_op> <ignore_js_op> 源碼安裝說明:伺服器空間需要 ...
  • 2016年新版 恆信六合彩系統 帶新開獎結果》》》》》玩法齊全》連碼自由對碰》各類玩法內附說明。資料庫文件 hs001 修改資料庫連接 文件夾 configs 文件config後臺管理 admin admin前臺會員目錄 member <ignore_js_op> <ignore_js_op> <i ...
  • 變數 String yourPast = "Good Java Programmer"; val yourPast : String = "Good Java Programmer" val yourPast = "Good Java Programmer" var yourFuture = "Go ...
  • 一、萊布尼茲發明二進位 1679年3月25日,萊布尼茲寫了題為“二進位算術的解釋”的論文。在文中,萊布尼茲給出了二進位的計數方法,系統地討論了二進位和十進位相互轉化的法則 ;並給出了二進位的加法與乘除法法則。但萊布尼茲要求不要馬上發表他的論文。在論文中他把二進位學術地位定位成“發明”。 1701年1 ...
  • 前幾天做了一個文件替換功能用到些python os的功能,感覺python os模塊的功能非常的強大,如果你希望你的python程式能夠與平臺無關的話,這個模塊是尤為重要的。即它允許一個程式在編寫後不需要任何改動,也不會發生任何問題,就可以在Linux和 Windows下運行,看到這裡覺得pytho ...
  • 平時用$_post[''],$_get['']獲取表單中參數時會出現Notice: Undefined index: ; 雖然可以通過設置錯誤顯示方式來隱藏這個提示,但是這樣也有隱患,就是在伺服器的日誌中會記錄這些提示,導致日誌文件異常龐大。 通過在網上搜索和自己自身的實戰總結幾種解決方法; 方法1 ...
  • 上回寫了[使用Redis實現關註關係][1],這次說說使用Redis實現Timeline。 Timeline的實現一般有推模式、拉模式、推拉結合這幾種。 推模式:某人發佈內容之後推送給所有粉絲,空間換時間,瓶頸在寫入; 拉模式:粉絲從自己的關註列表中讀取內容,時間換空間,瓶頸在讀取; 推拉結合:某人 ...
  • 項目中經常會遇到單例的情況。大部分的單例代碼都差不多像這樣定義: internal class SingletonOne { private static SingletonOne _singleton; private SingletonOne() { } public static Single... ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...