今天的博客中就來系統的整理一下“命令模式”。說到命令模式,我就想起了控制台(Console)中的命令。無論是Windows操作系統(cmd.exe)還是Linux操作系統(命令行式shell(Command Line Interface shell ,即CLI shell)都有命令行程式。說白了就是 ...
今天的博客中就來系統的整理一下“命令模式”。說到命令模式,我就想起了控制台(Console)中的命令。無論是Windows操作系統(cmd.exe)還是Linux操作系統(命令行式shell(Command Line Interface shell ,即CLI shell)都有命令行程式。說白了就是你輸入你要執行的命令提示符,然後電腦就還是根據你所下達的命令來執行。你最終看到的是命令執行後的結果,具體的執行細節不需要你一步步的去下達命令。(與之前博客保持一致,我們仍然使用Swift語言來進行實現)
進一步說,你下達的命令是一個總的命令,而電腦執行時是講該命令分為不同的階段來執行的。舉個簡單的例子,當你打開電腦是,你只需按一下開機鍵,也就是下達你的Start命令。此時電腦收都命令後就會執行硬碟啟動、點亮屏幕、載入系統等等一系列的操作,而這些操作都是你下達Start命令後其自動完成的。再比如,你使用Linux系統下的Shell時,你會在Shell中輸入各種命令,然後電腦就會根據你的命令來執行系列的操作,具體哪些操作是對外隱藏的。這也就是對具體的實現細節進行了封裝,並對外留出調用介面。
看完上面的描述,是時候回到今天的主題“命令模式”上了。命令模式簡單的說就是將一些列的命令(函數或者方法)進行封裝,隱藏內部執行細節,並對外留出調用的介面。命令模式是支持撤銷操作的,撤銷所做的事情就是與你剛纔下達的命令相反。下方就是命令模式的定義了,說白了命令模式就是進一步對命令進行封裝,簡化命令的執行。這些命令在編程中就是一個個的函數。也可以說“命令模式”是對函數調用的封裝,簡化了函數調用的方式,隱藏了函數調用的細節。
命令模式:將“請求”封裝成對象,以便使用不同的請求、隊列或者日誌來參數化其他對象。命令模式也支持可撤銷的操作。
今天博客中會通過命令模式來實現控制台是示例,也就是我們可以通過給控制臺下達不同的命令來進行不同的操作。
一、控制台命令模式的類圖
下方就是我們將要實現的控制台“命令模式”的示例的類圖。下方的類圖還是比較簡單的,紅框上方是具體的類(電腦和電燈)。這些具體的類中有屬於自己的不同的命令(對應著不同的函數函數),比如Computer類(電腦)中有Start、ScreenLight、Load、StartOver、Off等命令,而Light(電燈)類中有On、Off命令。
而紅框中是我們示例的核心,也就是對命令的上述具體命令的封裝。在封裝命令時我們會實現一個介面(該示例中是Command協議),該介面就是外部執行命令( execute() 函數)的介面。封裝的不同的命令都會遵循Command協議,所以我們封裝的命令都會對外暴漏一個execute()函數,用來執行我們封裝的命令。在封裝命令時,我們會根據封裝的命令的特點來執行特定的命令。比如下方的ComputerStartCommand命令中的就會包括Start、ScreenLight、Load、StartOver等子命令。也就是說在ComputerStartCommand命令中調用了Computer中的部分命令(函數),也就是對Computer類中的函數的調用做了進一步的封裝,所以ComputerStartCommand命令要依賴於Computer類的。
紅框下方就是我們的Console(控制台)類,Console是依賴於命令的介面而不依賴於命令的具體實現,這對模塊間的解耦是非常有用的。在Console類中的command屬性就是我們所依賴的命令介面,我們可以給command賦值不同的具體命令的實現,然後在Action函數中去執行具體的命令。請參加下方的類圖。
二、根據上述類圖進行代碼實現
上一部分對類圖進了詳細的介紹,接下來我們對上述類圖進行代碼實現就不是什麼難事了。我們實現的步驟是與上面分析的步驟是一致的,自上而下。首先我們會給出Computer與Light的實現,然後是紅框中的命令集合的實現,最後是Console的實現。如下所示:
1、具體命令執行對象的實現
首先我們要對真正去執行命令的對象進行代碼實現,在該實例中就是Computer類和Light類。當然從上述示例中,我們不難看出這兩個類要包括哪些命令(方法)。下方就是我們Computer類和Light類的具體實現,因為代碼較為簡單,在此就不做過多的贅述了。具體代碼實現如下所示:
2.對上述設備的命令進行封裝
下方代碼段就是上面類圖中的紅框部分的代碼的具體實現。我們將Command聲明為協議(命令對外的介面),而LightOnCommand、LightOffCommand、ComputerStartCommand具體的命令集合都遵循與這個協議。也就是說著三種不同的命令實現對外都有統一的介面,LightOnCommand與LightOffCommand都依賴於Light類,並且根據自己的命令種類來調用Light不同的方法,這也符合面向對象設計的單一職責。ComputerStartCommand命令類則依賴於Compute外設,會調用Computer中與啟動相關的具體子命令。具體代碼如下所示:
3. 控制台的具體實現
上面我們實現了類圖上面的兩個模塊,緊接著我們要實現類圖最下方的那個類,也就是Console類。Console類也是比較簡單的,Console類依賴於Command介面,其中的command存儲屬性就是用來存儲那些遵循Command協議的類的對象的。在Console類中的action()方法是用來執行命令的。具體實現如下。
三、測試用例
經過上面的類圖的介紹與具體的代碼實現,相比對“命令模式”有點概念了吧。最後一部分我們要對上述代碼的實現進行測試,看一下我們的代碼實現是否有問題。下方代碼截圖就是我們的測試用例以及該測試用例執行後輸出的結果。首先我們創建了一個控制台的對象(類似於我們打開了一個Shell視窗),然後輸出不同的命令(setCommand()),最後進行執行(調用action())。測試用例具體如下所示:
至此我們的“命令模式”的一個完整示例就執行完了,最後用一句話來總結一下命令模式,那就是“命令模式是對一些列函數的調用的封裝,然後留出執行的介面”。
同樣今天的Demo也會在github上進行分享,分享地址為:https://github.com/lizelu/DesignPatterns-Swift