久違的更新又能寫一篇新的文章,實在是很開心。已經太久沒有咬文嚼字,文感可能都已經跑掉了也說不定。這一年來經歷了很多,心境上也有不小的變化,甚至還習得了一些新的技能,也許能有新的發揮,但我更害怕的是原有的東西會被取代,人總是這樣喜新厭舊的。
好了,回到正題吧。最近拿出一年前自己用C寫的通訊錄,我自己是覺得沒有到慘不忍睹啦,但還是有很大的進步空間。當時對於模組化的概念雖然有,但非常薄弱,也頂多就是做了幾個不同的模組(.c/.h),就拿我現在描述的模稜兩可應該也能略知一二了。
這麼說吧,一年前的專案僅有四個檔案,分別是:兩個.h,兩個.cpp。所以如果扣除掉main.cpp就剛好剩下兩個模組了。而其中一個標頭檔是DLL函式庫的,一個.cpp是main,也就是主程式函式所在的地方。相當於我只有一個模組,而所有的程式都是在這個模組中完成的,main只負責呼叫這個模組內的這些函數。這樣寫當然沒甚麼問題,反正只要能執行沒出錯就沒問題了不是?
但……程式設計的領域可沒那麼簡單,上述的設計方法有甚麼問題呢?簡而言之,當所有的程式碼都擠在一起時,假設某個部分出錯了,你得花上不少時間才能知道到底是哪邊出了錯。程式這東西是這樣,『牽一髮動全身』,幾乎所有資料都是有關聯性的,但良好的設計卻可以達到簡潔易讀的程式碼和提高程式的彈性,也能達到所謂的「高內聚、低耦合」。什麼意思呢?簡單的來說就是「獨立性」,當然我們還是得要讓資料能產生關聯,不然如何作動呢?但我們可以想辦法讓他不那麼互相依賴。假設今天我換了個模組進來,我只要改動少部分code的,這個模組一樣可以通用,這樣就是所謂的獨立了,也就代表這個程式是可以很彈性的。不過要理解這段話,並非那麼容易的,如果看文的你不像筆者是個笨蛋的話,也許能夠很快地明白也說不定XDD
後來呢,我正好在學C++想說想應用新的東西到舊東西上,於是我向我的的指導老師提出了改正方案,老師給我了個方向—「MVC」。當下我便直接去查找資料,閱歷各種與MVC有關的文章,最後呢……概念是懂了,但實作上還是有一定程度的障礙,可能是我太笨的原因XD。於是歷經各種千辛萬苦,總算是做好第二版。但當我繳交作業給指導老師的時候呢,詢問他是否有像了,老師回答:「一點點點……」(囧rz)
這一點點點代表我還差很遠啊!明明是我嘔心瀝血的成果的說。但我不氣餒,繼續的查找資料,繼續地請教許多人,最後還是多虧老師的提示才得以完成,當然我也努力過了,並非一開始就去要答案,這點我還是可以很自豪的。其實學東西就是這樣,不論你學甚麼,一開始難免會遇到挫折或瓶頸,也許靠自己的真的跨不過去,但至少,你嘗試過、你撞牆過,你知道這樣行不通時,這時再去繞個路走。因為這些都是你學習、成長的良藥,因為你才會記得這些挫敗;而不要一開始遇到困難就不加思索的去找人要解答,這樣即便你學會,但得到的卻不是你自己的。成果跟過程都很重要,但我認為過程是最重要的,因為它代表了經歷,沒有這些過程,又如何達到成果呢?
稍稍離題了,最後當然很順利的第三版完成,也得到指導老師的認可,說這樣大致上就是有像了,當然我不確定在其他人或是其他高手的眼中是如何看待我所學習到的答案是不是正確的,但至少我能很自豪地說,這是我自己學習研究的成果,而不是從網路上抄來的答案,我也可以詳細的解說為什麼我這樣設計。
那到底什麼叫做MVC呢?關於這點就是眾說紛紜啦~不然我也不會花這麼多時間在查找資料。簡單來說,他是一種設計模式,利用Models、View、Controller這三個模組所完成的程式,MVC就是取名自這三個模組的頭字。那麼為什麼要運用MVC來開發呢?因為啊,他將程式碼分成三個不同的功能,每一個模組有自己要完成的事;這樣的設計下每個模組分工明確,能夠簡潔程式碼,在後續維護或著擴充功能上,也能更有彈性的易於修改,因為出錯了,你可以很輕易地得知是邏輯出錯了還是畫面出錯了。
有人說MVC模式很難理解,這點倒是真的;但當你自己實作之後,其實也沒有那麼複雜難懂,但開發起來的確是有點費功夫。具體的做法呢我就簡單地稍作說明。
首先你會有三個模組要完成,分別就是Models、View和Controller,這三個模組各自的功能如下:
Models:模型,用於存放資料、處理資料邏輯,它具有存取資料的權限。
View:視圖,用於顯示資料,方便使用者能夠看到資料處理的結果。
Controller:控制器,用於輸入資料,將使用者輸入的資料放入Models中,不過也有人說他要負責處理流程。
我的作法則是,另外做一個流程管理者模組,例如MVC_ProcessManager,所有的流程由此模組管理,而Models單純只做資料庫的存取,View單純只做資料的輸出,Controller單純只做資料的輸入。
做出來的感覺大概就是像這樣
class MVC_ProcessManager
{
public:
Models *pModels;
View *pView;
Controller *pController;
//-------------------------
void Example();
};
void MVC_ProcessManager::Example()
{
while (1)
{
pView->DataShow( pModels->DataGet() );
pController->DataInput( pModels->DataIn() );
}
}
像這樣,ProcessManager提供的就是一個介面,讓這三個模組交互作用。這樣即便是把其中一個模組換成別的模組,比如說不同字樣型式的View或著是不同的資料庫(Models),我也僅要修改少部分的程式碼就可以達到我要目的。而透過這個流程管理者,三者本來都是獨立作業,每一個有自己負責的工作,也能內聚在一起,提升了內聚力、降低了耦合度。
簡單的講解上述這個簡短程式碼範例,這個模組包含了三個物件,他們各自可以存取自己的類別成員,在函式Example()中,用一個while迴圈呈現流程的循環。在一開始使用者需要看到畫面對吧?所以我們透過物件pView去存取View的成員函式DataShow(),讓畫面顯示呈現出來,但畫面顯示的是什麼資料呢?所以我們透過pModels存取Models的成員函式DataGet(),得到資料的回傳值後當作參數傳給DataShow(),如此一來DataShow()就能知道他要顯示甚麼樣的資料內容對吧 ?這樣講太複雜嗎?沒關係,之後會用第二篇更詳盡解說,記得在下方留言告訴我你的問題。
接著繼續說,顯示了我們要的資料後,這是一個輸出功能對吧?那麼有輸出必然要……有輸入,沒錯。所以呢,我們就用Controller讓使用者可以輸入他想要的放進去的資料。所以讓pController去存取DataInput(),這個函式呢就是專門處理資料的輸出入。但DataInput()要怎麼把資料放入Models呢?沒錯!就是透過pModels去存取DataIn()將資料放入。
聰明如你一定會覺得既然有一個Models::DataIn(),為何還要透過Controller::DataInput()這麼囉嗦。這是為了建立一個好的架構,我們前面提到為何要採用MVC的設計呢?就是為了提昇內聚、降低偶和嘛~
所以如果你直接透過Models::DataIn()去做資料的寫入,這樣子做法不僅失去了嚴謹的架構並且相當於你在Controller::DataInput()要做的事,要移到了Models::DataIn()去完成,那就等於你Controller失去作用了。簡單來說呢,他設計這三個機制,就是Controller輸入資料、View輸出資料、Models處理資料,各自只要做好自己份內的工作,它不需要管其他模組是怎麼樣運作的。這樣做法好處就是前面一直在說的:「高內聚、低耦合」了。
在第二篇當中會詳細示範上面沒寫到函式實作如何完成,並且會比較前一段所提到的差異比較,如果看到這邊還不懂的話,那也沒關係。你只要知道,在MVC的設計理念中,最重要的就是讓每個人都「各司其職」。今天我採取這樣設計的好處呢,我可以很清楚知道,當我今天顯示時資料不對的時候,到底是我的哪一個環節出錯了。因為你每個模組都是獨立運行的,Models並不關心View如何顯示他的資料,View並不關心Controller如何將資料輸入進來,只需要在ProcessManager當中將他們整合再一起,讓流程可以順利進行。當你今天要擴充新功能時,也非常便捷。假設你今天可能只是想改顯示的部分,比如說字樣或字型,那你只需要針對View的模組去下手,即便你在View做了許多更動,卻也不會影響到其他模組的運行。比如你只是針對顯示下手的,所以更改View模組的內容,但其他功能又沒動到,流程也不需要更動,對吧?
試想,如果你的程式碼都擠在一起,結果你要增加新功能進來,那豈不是改到瘋掉了?你得花更多的時間在小心除錯以及程式碼的修正,而且是每次修改都要花費許多心力;但倘若你一開始花多一點心思跟時間在設計,那麼後續你僅要花費少量時間就可以達到你的目的,是不是很棒呢?
也差不多是該收尾了,以上就是我的簡單的心得分享,大致上只是粗淺的講解一下,如果還是有不懂的地方,歡迎來詢問我。我是車一平八,我們下次見囉!