設計模式/軟件設計模式Oesign pattern)是軟件設計過程中的經驗總結。可 以讓程序代碼易重用、易理解、更穩定。目前總結出來的模式有23種之多,文中主要涉及 “工廠模式”在多串口通信軟件開發中的應用。作者針對衡器稱重系統中常用的儀表、一機一
秤、一機多秤等應用場景,提出相應的解決方案。
1.引言
在軟件開發過程中,常常會碰到相似問題, 做重復的工作。如何提高效率,保證代碼的可靠 性,可重用性昵?前人總結出了很多軟件開發模 式,來解決相應的問題。文中將針對“軟件設計 模式”一“工廠模式”在多串口通信軟件開發中 的應用展開描述。
2.設計模式簡介
設計模式(Oesign patten)是一套被反復使用 的、多數人知曉的、經過分類編目的、代碼設計 經驗的總結。使用設計模式是為了重用代碼、讓 代碼更容易被他人理解、保證代碼可靠性。最早 提出設計模式思想是在1994年,由Erich Gamma 等人,在其所著的《面象對象的可復用元素》一 書中提出的??偨Y出三大類別創建型模式、結 構型模式、行為型模式,六大原則(開閉原則、 里氏原則、依賴倒置原則、接口隔離原則、迪米 特法則、合成復用原則,23種設計模式俱體內 容請參看相關書籍。本文將重點介紹:工廠設計 模式。它屬于“創建型模式”,即在創建對象的過 程中,隱藏創建邏輯,這使得程序在創建給定實 例對象時,可以提供靈活的判斷。
3.衡器軟件中的問題
作者長期從事衡器稱重軟件的設計。在長期 的工作經歷中,參與了很多項目,其中多數都會 用到串口通信。會遇到以下幾種典型的應用問題:
(1)在使用衡器儀表時,串口是常見的對外通 信方式。稱重儀表廠家多,型號不一,通信格式 各不相同。能不能使用統一的開發模式,進行管 理,減少重復性的工作昵?
(2)地磅稱重管理中,有“一機一秤”,也有 機多秤”的模式。在多秤同時使用時,儀表型 號可能相同,也可能不同,有沒有簡潔、高效的 擴展軟件代碼的方法昵?
4.工廠設計模式
針對上述問題,作者通過實踐和總結,覺得軟件開發模式的中的“工廠模式”比較適合解決 這類問題。
什么是“工廠模式”?顧名思義,就是客戶提 交“訂單”,交給“工廠”生產,最后得到“產 品”。“工廠模式”模擬了這個過程。“工廠模 式”分為三種子類別:簡單工廠、工廠方法、抽 象工廠。這三種方法,本質相同,但各有其應用 場景,簡單來說,如下:
(1)簡單工廠:一個工廠生產多種不同產品。
(2)工廠方法:多個工廠,每個工廠生產一種 產品。是對“簡單工廠”的改進,因為“簡單工 廠”不符合“開閉原則”。
(3)抽象工廠:多個工廠,每個工廠生產一種 或多種產品??梢愿鶕?/span>“訂單”需求,生產“產 品”。“訂單”中可能存在多種不同的“產品”需 求,可以交給不同的“工廠”來“生產”。
這三種模式都能解決衡器軟件中的儀表串口 通信問題。文中重點講解“簡單工廠”和“抽象 工廠”這兩種模式,這兩種模式比較容易理解, 其它的模式也可依此類推。
5.面向對象的實現過程
設計模式的運用與編程語言無關。作者以常 用的C++語言為例,說明面向對象的封裝過程。
首先,作者封裝了一組串口通信類,將串口 通信過程中,常用的的方法,封裝在一個類族里, 為后期模式設計提供基礎如圖1所示。
串口類庫可根據需要不斷擴展,封裝好后, 與下文的設計模式類隔離,減少代碼耦合。這個 類族中的底層子類,相當于“工廠”里生產的產品
(1)簡單工廠的實現過程
簡單工廠模式如圖2所示,將“產品”實例的創建放到工廠方法中完成,從而為“產品”的選擇提供靈活性。這里的“產品”就是儀表型號,工廠就是 TMeterFactory 類,其方法 CreateMeter 可以創建各種儀表的實例。
主要部分的偽代碼如下:
#include
classTM eterfactory//儀表工廠類
{
Private:
m ap
TM eterfactory0;
ICommO bject*C reateM eter (char*strM eter- Name);//創建儀表實例方法
~TM eterFactoryO;//銷毀儀表類實例
};
ICommObject*TM eterFactory::CreateM eter (char*strM eterN am e)
{ //檢查儀表實例是否存在 ifm _m eter.end )!=m _m eter.find (strM eterN am e)) return m_m eter.find strM eterN am e)->second; //創建新的儀表實例 ICommO bject*pM eter=N ULL; if(!strcm p "X K 3190A 9",strM eterN am e)) pM eter=new TXK3190A9 0; else return NULL;
...//繼續添加代碼,創建其他儀表型號 m_meter.insert std ^:pa ir
}
客戶端調用代碼如下: charweight[10]={0};
TMeterFactory*pFactory=new TMeterFactory;
ICommObject*pMeter=pFactory->CreateMe-
ter(“XK3190A9”);
strcpy(weight,pMeter->read());// 讀取重量,中間省略 open,write,close 等方法代碼
上述過程中,可以看到:在使用簡單工廠模式 (或其它模式) 時,并不一定能減少代碼量,但是易于后期擴展和理解。從客戶端的調用代碼可以看出:模式提供了統一的接口,調用者只要給出儀表型號,就能得到相應的類實例。實例創建過程封裝到其他代碼塊中,只要那部分代碼沒有問題,調用者就能得到正確的結果,相當于黑盒操作。這種方式,適合多人分工合作,共同開發軟件。
(2) 抽象工廠的實現過程
“簡單工廠”模式適合“一機一秤”的稱重軟件開發。“抽象工廠”模式適合解決“一機多秤”的稱重模式。他將儀表實例創建過程推遲到子類中完成,從而為“訂單”中的多種“產品”組合提供機會。以下是“一機一秤”和“一機兩秤”類圖如圖 3 所示。
由上圖可以看出,每一個“工廠”代表一種稱重模式,可以從“一機一秤”,擴展到“一機 n 秤”。而每一種稱重模式中,可以用同一種型號的儀表,也可以用不同種型號的儀表組成系統。具
體實施時,可根據需求選擇。C++ 偽代碼如下: class ICommObject;
class IFactory // 抽象工廠
{
public:
virtual ICommObject * CreateMeter1()=0; // 創建儀表 1,此處為純虛方法
virtual ICommObject * CreateMeter2 ()=0; // 創建儀表 2
// 可以繼續添加 protected:
IFactroy();
};
Class TOne_pc_and_one_scale:public IFactory// 具體工廠:實現一機一秤功能
{
public:
ICommObject * CreateMeter1 () {return new TXK3190A9;}
};
Class TOne_pc_and_two_scale:public IFactroy// 具體工廠:實現一機兩秤功能
{
public:
ICommObject * CreateMeter1(){return new
T8142pro;}
ICommObject * CreateMeter2(){return new
XK3180;}
};
客戶端調用代碼如下: // 一機一秤調用方法
char weight_A9[10]={0};// 重量字符串
IFactory * pScale=new TOne_pc_and_one_scale;
ICommObject * pA9=pScale->CreateMeter1();
strcpy(weight,pA9->read());// 讀取重量到 weight
中,中間省略 open,write,close 等方法代碼
// 一機兩秤調用方法 char weight_8142[10]={0},weight_3180[10]={0};//
重量字符串
IFactory * pScale=new TOne_pc_and_two_scale; // 創建工廠實例
ICommObject * p3180=pScale->CreateMeter1(); ICommObject * p8142=pScale->CreateMeter2(); strcpy (weight_3180,p3180->read ());// 讀取重量
到 weight_A9 中,中間省略 open,write,close 等方法代碼
strcpy (weight_8142,p8142->read ()); // 讀取重量到 weight_814 中
使用“抽象工廠”模式,在添加新的“工廠”時,并不影響已有的“工廠”代碼,已有的代碼基本不需改動,提高了程序的穩定性,符合“開
閉原則”,因此成為 23 種軟件設計模式之一。
6.工廠模式在稱重傳感器溫度測試軟件中的應用
作者在編寫 《傳感器溫度測試軟件》 的過程中,使用了數據采集板,每個板上有一個串口,多塊板同時向上位機發送傳感器的實時溫度測量數據。利用“抽象工廠設計”模式,很好的完成了軟件編寫。原來在其他軟件中的通信代碼 (即圖 1),移植過來使用,進行部分擴展,實現了代碼重用。軟件可以對每一個串口的通信數據和通信參數,進行單獨的管理。如下圖:
7.相關問題討論
在 Windows 系統中,某個“串口”設備,在某一時刻,只能被一個軟件使用 (虛擬串口設備除外)。多個進程或線程同時使用,會產生沖突。沖突的情況分為三種:
(1) 兩個 (或兩個以上) 不同的軟件,同時打開同一個串口
(2) 同一個軟件,運行兩次實例 (或兩次以上) 在內存中,同時打開同一個串口
(3) 同一個軟件,運行一次,但在軟件內部兩次(或兩次以上) 打開同一個串口
①、②兩種情況涉及不同進程之間的資源搶占的沖突,可以考慮用進程互斥的方法解決,不屬于軟件模式的解決范疇。
對于第③種情況,可用“單例模式”解決軟件內部多次、同時讀、寫同一個串口沖突的問題。
“單例模式”的目標就是:每個類只能創建一個實例。類的“構造函數”和“拷貝構造函數”設為“私有”或“保護”權限,類實例由其靜態成員函數創建。
文中的“工廠模式”也涉及到串口的調用,因此可能有人會問:“工廠模式”能否結合“單例模式”同時使用呢?答案是否定的。“單例模式”封裝的對象是“串口”硬件實體。本文中的“工廠模式”是以“稱重儀表”為對象,進行封裝。兩者的出發點和角度不同,雖然都用到了串口通信,但是功能需求不同。物理串口,同一時刻,只能被一個實例使用,因此用“單例模式”比較合理。而“稱重儀表”類,則存在多臺相同型號的儀表同時使用的情況,所以需要創建同一個類的多個實例。這些屬于面對的編程思想,需要結合實踐去體會他們的異同。
8.總結
在軟件設計過程中,不僅衡器稱重軟件“一機多秤”(即一臺上位機,多臺稱重儀表同時工作),可以使用“工廠模式”來設計,其它類似的—涉及多臺儀表,多個串口同時工作的軟件,都可參考這種模式。軟件模式的使用,使代碼易于閱讀,管理,能提高代碼的重用效率。實際軟件開發中,具體使用哪種模式,是一種模式,還是多種模式混合使用?對于開發者來說,需要有一定行業經驗,總結出用戶的需求,整理出規律性的內容,再選擇合適開發模式,才能找到一條正確的道路。