20.VB用集合與數組模擬.NET里的哈希表類型
dim c as new collection c.add Array("sx","數學"),"sx" c.add Array("yw","語文"),"yw" c.add Array("en","英語"),"en"
也可以用對象來代替數組,可讀性更好:
Dim x As New Collection Dim km1 As New CKeMu km1.KeMuId = "sx" km1.KeMuMC = "數學" Call x.Add(km1, km1.KeMuId) Dim km2 As New CKeMu km2.KeMuId = "yw" km2.KeMuMC = "語文" Call x.Add(km2, km2.KeMuId) Dim km3 As New CKeMu km3.KeMuId = "en" km3.KeMuMC = "英語" Call x.Add(km3, km3.KeMuId)
類CKeMu就兩個屬性:
Public KeMuId As String Public KeMuMC As String
21.避免硬編碼值
硬編碼就是在程序里寫死為一些數字、字符等, 而通常這些數字字符可能會變化的,如果很多地方都寫死這些數字,將來調整起來就非常麻煩。
當然,可以定義一些系統(tǒng)級全局常量,這樣將來更改 起來可能會方便一些,另外,基于配置的方式來編寫程序可能修改與維護更為方便,比如資源文件、數據庫來存儲這些可配置的數據。 硬編碼值容易寫錯,比如這個窗體是這個,那個窗體是那個,多個程序員一起開發(fā)可能問題會更多,手一抖就有可能打錯,打錯了,也不會象寫錯變量名一樣有錯誤提示, 22.每個窗體、模塊、類模塊里開頭都加上 Option Explicit
這也許是最基本的規(guī)定了,但很多時候都忘記加這個東西, 菜單:工具-選項,勾上“要求變量聲明”
勾上后,以后增加窗體或模塊時,自動會加上 Option Explicit 這個東西上去,
但很多時候維護一些舊的程序,他們都不勾這個選項,一勾就可能有很多問題。
硬編碼一節(jié),如果是數據庫或者資源文件里,應該對一些關鍵的系統(tǒng)數據進行控制,防止有意或無意的錯誤修改系統(tǒng)數據, 比如數據庫的一些系統(tǒng)設置表,應該設置日志跟蹤,根據所有的修改,設置觸發(fā)器,對所有修改進行驗證與控制,設置訪問的權限等等,并且在安裝使用之前配置好所有系統(tǒng)數據。
VB的Collection無法枚舉所有key值,所以采用存儲對象的方式,將key存在對象里,這樣就可以枚舉key值了, 另外,集合還要能判斷是否存在某個key值,
23.更改窗體的文件名
如果要更改窗體文件的文件名,應該在IDE里打開窗體然后另存為。如果直接修改文件的名字,那連同對應的frx文件名也要更改,即使frm和frx兩個文件的文件名都改了,還不行, 還必須把frm文件里引用frx文件名的地方也都改了才行, 用記事本打開 frm 文件,找到那些引用 frx 文件的地方,一個個都改過來才行。
24.關于層的設計
前面說過,一些語言里,在某個窗體里調用別的窗體,你不能訪問別的窗體里的控件,不能直接得到控件的屬性方法,因為那些控件都是受保護的,但VB是例外,這很容易導致混亂,作為一個內部運行的窗體,外界過多的干預,職責沒分清楚,會怎么樣? 所以才有接口的概念,接口其實很簡單,就是提供給外界可以操作的東西,而窗體自身的控件,是不應該給別人操作的, 這是層設計的一個規(guī)矩,就是職責要分清,各做各的,互不干涉,如果需要交互,只能通過約定的通道進行交互。
如何分層,對于大多數的信息系統(tǒng),通常的分層可以參考一些MVC的分層方式,以及VC的Document/View分層方式, 無論采用哪種,都要分清楚職責,但不要照搬,照搬只會帶來更多的危害,不會帶來更多的幫助,“建設有VB特色的分層設計” 比如視圖,可以建立一個視圖層,專門封裝一些對界面操作的公共類,比如表格的操作,表格的格式控制,排序等等,比如文本框的輸入控制,控制只能輸入數字、字符,比如下拉框的綁定、取值,等等都可以封裝,以及更多其它類型的組合封裝,比如權限設置的兩個列表框移動數據,上下兩個表格的連動關聯,等等,
業(yè)務層的封裝,需要分清楚,業(yè)務層不要牽扯到界面,業(yè)務類里不會調用任何控件,如果調用控件,那就是職責沒分清, 其實業(yè)務層細分的話可以分業(yè)務層、數據層, 但實際業(yè)務層和數據層沒必要分的那么細,但對于一些復雜的業(yè)務邏輯,可以分的更細,業(yè)務層控制流程,定制流層, 業(yè)務層和數據層分開,對于有復雜的流程的地方,比如SAP的ERP定制流程就非常有意義了,不過通常意義不分開也行,因為流程控制可能各層都會牽涉得到,無法單靠某一層就能完成流程控制, MVC里的C這一層能控制一些流程,但MVC也只能在Java里應用得非常好,而Java都是做網站的,網站的界面可以全部自動生成, 而在C/S模式下,這種方式很難實現,復雜的界面控制,輔以復雜的業(yè)務流程,都限制了MVC模式的應用,所以只是模擬實現,而不是照搬。
24.變量盡量限制在最小范圍里使用
盡量不要用全局變量,窗體級變量、模塊級變量也盡量少用, 能在函數里定義的變量,就不要定義為窗體級變量, 如果定義為窗體級變量,什么時候變量被銷毀了,狀態(tài)被改變了,你都不知道,如果再使用變量就會出錯, 你在這個函數里使用變量,然后銷毀它,認為沒問題了,但其它函數也用這個變量,也就會存在問題, 窗體級變量實際也是公共變量,類似于全局變量,只不過使用范圍只能在窗體里使用而已。
函數里聲明變量時,最好用到時再聲明,越遲聲明越好, 避免聲明一個變量,然后在后面很遠的地方才用到,
25.變量命名的規(guī)則
對于一些模塊里定義的方法,最好加上“Pub_”前綴,當然具體是什么前綴根據項目約定來加,但一定要有前綴區(qū)分開來,一則避免名字沖突,二則一看就知道是全局函數。
窗體級的變量統(tǒng)一加上m_前綴,以什么做前綴也可以根據項目約定來加,
函數的參數統(tǒng)一加上p前綴,并且第二個字母大寫, 如: Private Sub ShowData(pRs AS ADODB.Recordset)...
這樣看函數體的代碼時,一看到p前綴就知道是參數, 控件的命名可以參考相關的規(guī)定,不贅述,
一些普通變量的命名,比如函數里聲明的變量,沒有實際規(guī)定, 一般數量用n前綴,字符串用s前綴,索引用i做前綴,對象用o做前綴,對象也可以添加具體的前綴,比如 Recordset 對象用rs做前綴,等等,盡量增加代碼的可讀性,并保證代碼的簡潔,輸入方便快速。
循環(huán)變量統(tǒng)一用i,j來命名, 而且i,j不要再定義為其它用途的變量,只用做循環(huán)變量,
上面說了變量的前綴, 前綴之后的命名,一般變量要可讀性強,最好一看就知道意思, 好的代碼是自描述的,不用添加注釋也一看就懂(當然注釋還是要有的)。 變量通常采用縮寫的方式,縮寫有時很難看出全稱來,如果看不出來, 那就用全稱,一些常用的名詞,項目需要定好縮寫約定,統(tǒng)一縮寫名稱, 另外,如果采用拼音,最好拼完所有單詞,不要用縮寫,因為縮寫很難猜出意思, 盡量避免用漢語拼音做變量名,有時間多學學英語,如果不知道英語名字, 可以借助一些翻譯工具翻譯出英文名字,翻譯也是很有講究的,因為同樣一個詞語, 翻譯成英文可能有很多翻譯結果,如何選擇,所以平時多閱讀一些英文雜志, 知道它們的英文表達方式。 有的翻譯不出來的,也可以用漢語拼音,漢語拼音盡量用全稱,縮寫很難拼出結果。
27.平常注意整理一些公用函數出來,這樣可以省略大量的重復的代碼,而且可以避免一些重復性的出錯。
比如數組的處理,我定義兩個函數處理數組,這兩個函數在使用數組的地方用的非常多:
Dim i As Long, currRow As Long currRow = vsFormat.Row For i = 0 To m_ArrLen(comboTitles) - 1 m_ArrAdd aPrevVals, cellText(currRow, comboTitles(i)) Next i
上面我用到兩個自定義的處理數組的函數:m_ArrLen、m_ArrAdd
數組最好規(guī)定一下,下標統(tǒng)一用0來表示,其實VB里不好的地方就是有些地方下標是0,有的地方下標又是1,有點無所適從的感覺, 我定義的動態(tài)數組,下標統(tǒng)一全部用0表示,這也是為了與其它語言統(tǒng)一,沒辦法,用的語言太多了,不統(tǒng)一一下,問題更多。
m_ArrLen 是用來獲取數組長度,VB里沒有獲取數組長度的函數,只有一個 UBound 用來獲取上標,而其它很多語言都有獲取數組長度的函數,特別是遍歷數組時,用 for i = 0 to ArrLen(Arr) 的方式,幾乎成為一種標準,其實也可以用其它很多種寫法,但除非是特殊需要(比如要從最末尾開始遍歷),最好統(tǒng)一一種寫法。 很多人寫代碼,特別是新手,似乎為了展現自己高超的編程水平一樣,這里用這種寫法,那里用那種寫法,很簡單的問題,搞出四五種寫法,實際上一種寫法就行了。不應該弄一些怪異的寫法來證明自己的水平高,而應該通過解決實踐中的問題來證明自己的水平。 用戶承認才算。
'-- 0.4.1 數組元素個數 : arr=數組 Public Function m_ArrLen(arr) As Long On Error Resume Next m_ArrLen = UBound(arr) + 1 If Err.Number <> 0 Then m_ArrLen = 0 Err.Clear End If End Function Public Function m_proLen(arr() As FindItemProperty) As Long On Error Resume Next m_proLen = UBound(arr) + 1 If Err.Number <> 0 Then m_proLen = 0 Err.Clear End If End Function
說明,這兩個函數也只是在數組元素比較少時才這么用,如果有上萬個數組元素,最好自己采用最優(yōu)化的方式來做。
'-- 0.4.2 數組增加元素 : pArr=數組,pVal=元素值 Public Function m_ArrAdd(pArr, pVal) Dim length As Long: length = m_ArrLen(pArr) ReDim Preserve pArr(length) 'pArr 必須是數組 pArr(length) = pVal End Function Public Function m_ProAdd(pArr() As FindItemProperty, pVal As FindItemProperty) Dim length As Long: length = m_proLen(pArr) ReDim Preserve pArr(length) pArr(length) = pVal End Function
公共函數的整理是件相當耗時間的工作,是經驗與積累的結晶, 需要反復錘煉才能寫出好的公共函數,如果整理好后,可以按分類進行封裝。
但公共函數的整理也是有一定問題的,就是多用戶開發(fā)時,可能別人并不習慣使用你整理出來的公共函數,他們要學習你定義的函數,他們不會很樂意,如果你是無名之輩,他們更加不樂意去學,即使你寫的很好。
所以整理公共函數也要有節(jié)制,就是如果能用系統(tǒng)函數就用系統(tǒng)函數。 '-- 0.4.5 搜索元素索引號 Function m_Index(pArr, pTitle) As Long m_Index = -1 Dim j As Long For j = 0 To m_ArrLen(pArr) - 1 If Trim(pArr(j)) = Trim(pTitle) Then m_Index = j Exit For End If Next End Function
'-- 0.4.6 數組連接成字符串 兩種方式:一維數組、鋸齒數組取索引(有個子數組索引號) Function m_ArrJoin(arr, splitNv As String, Optional rank As Long = -1) As String Dim i As Long, str As String: str = "" For i = 0 To m_ArrLen(arr) - 1 If rank = -1 Then str = str & splitNv & Replace(arr(i), splitNv, ",") Else str = str & splitNv & Replace(arr(i)(rank), splitNv, ",") End If Next m_ArrJoin = mID(str, Len(splitNv) + 1) End Function
'-- 0.4.4 元素值是否在數組里 Public Function m_inArr(pArr, pVal) As Boolean m_inArr = False Dim i As Long For i = 0 To m_ArrLen(pArr) - 1 |