best practice 封裝存儲過程(續4)——越抽象,就越容易封裝變化。


 

上回書 Tony  says

看起來它似乎並沒有改善不同層次代碼的耦合關係,以前例看,所有的針對數據庫的調用都是通過C#層的RunProc實現的,似乎它本身就充當了隔離層的作用,爲什麼還要增加一個無用的層delete_dept(1)呢? 

 

你的問題提的很好。我會更加細緻的解答你的疑問。

 

簡單說,delete_dept語義上比RunProc更加抽象,沒有那麼多的細節,因此更加容易封裝變化。

 

首先,我們從使用者角度考慮,本地函數或者Runproc方法的時候,那一個更加簡單。

 

是的,函數也是有客戶的,函數的客戶就是它的調用者。我們看一個函數設計的好不好,關鍵要看對客戶的代碼是否隱藏不必瞭解的細節。

還是以代碼爲例來看,  當客戶代碼,比如button_click()內調用 

  RunProc("delete_dept",1)我們看RunProc需要用戶瞭解那些信息:

 

1.          這是一個調用存儲過程的方法

2.          這個存儲過程名稱是delete_dept

3.          這是部門的編號是1

而使用代碼delete_dept(1)客戶並不需要知道在RunProc內需要了解的信息12。當然3還是需要了解的。

我們再細緻些,對比下兩者的語義:

 

 

語義

delete_dept(1)

我要刪除一個id=1的部門。

  RunProc("delete_dept",1)

(當前數據庫連接下),調用一個叫做delete_dept存儲過程,參數爲1

 

我們每個人都做過客戶,比如說做過裝修的主人家,都知道和裝修公司說,“恩,不要給我說那麼多的細節,我就關心是否達到了我想要的效果”。對嗎?

體驗以下兩者的語義,使用delete_dept(1),和使用RunProc("delete_dept",1)相比,哪一個讓你這個客戶更加輕鬆?

 

因此,用語義分析上看,delete_dept(1)只是說做什麼,RunProc則是說如何做。這就是層次上的差別了。

 

其次,我們看看兩者如何封裝變化。要知道,軟件的的最大問題在於適應變化。一個客戶需求的變化,最理想的情況下,我們希望在一個地方解決,而不是到處修改。

那麼,刪除一個部門會有什麼的變化呢?我經過整理,找到大家提到了的幾個可能的變化

1.          存儲過程命名不合適,需要修改

2.          需要考慮更多的錯誤處理

3.          需要用戶給出更多的參數,比如 讓用戶自己輸入部門的名稱,加以驗證。

 

爲了便於分析,我們假設整個程序有3個地方需要調用刪除部門。僞代碼如下:

 

Button1_click()

{

     delete_dept(1) 

}

Button2_click()

{

     delete_dept(1) 

}

 

Button3_click()

{

     delete_dept(1) 

}

 

delete_dept(id)

{

   RunProc('delete_proc',id);

}

限於篇幅,我們只能舉出這樣的小例子:請稍微想象以下,這些調用(如button-click 可能分佈在很多單元內。

 

我們來對比下兩種情況下需求的變動,會導致多少個函數需要更新:

 

 

 

修改點

修改點

情況

localfunction

Runproc

1

1

3

2

1

3

3

5

4

 

看到這個數字,你並不覺得怎麼樣。可是當你把3換成100的時候,也許就不這麼想了。

 

 

修改點

修改點

情況

localfunction

Runproc

1

1

100

2

1

100

3

102

101

合計

103

301

 

就是說,3個變化同時發生的情況下,前者需要修改103個函數,後者是301次。如果僅僅頭兩個發生的話,那麼前者2次,後者200次——這就是差別——當調用增加的時候,我們考慮問題必須進入新的視角:在比較少調用的情況下,代碼差點沒有關係;當調用很多的時候,我們必須錙銖必較

 

100個調用是不算什麼了。我們的checkError方法,我統計是1900多次調用,檢查權限是990多次調用,更不要說更加基本的函數了。

 

前兩情況,體現了我們一直以來 的一個最高理想——客戶的一個需求變化,只要在一個地方就可以修改完畢。其中這樣的變化僅僅看名稱就看得出來。使用delete_dept(1),比RunProc需要了解的細節更好,因此,當細節變化發生的時候,前者更加容易封裝變化。

 

可是,有人一定會說,第三種情況修改的點還是很多啊。你的封裝不管用啊?

首先,不管有多少引用,兩者的修改點都僅僅差一個,因此可以認爲等同。其次,封裝僅僅可以封住我們考慮到的情況,而不是所有情況。這種情況下,整個函數因爲加入了參數,語義都已經發生了變化,是不是叫做delete_dept都不一定了,此時還要封裝,就勉爲其難了。再好的封裝都不能解決所有問題,我們要做的是,儘可能的封裝變化,而不是封裝全部變化——這是永遠也不可能的。

發佈了4 篇原創文章 · 獲贊 0 · 訪問量 2301
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章