軟體開發中的矛盾——一個簡單的例子 (轉)
在以前的文章中,我曾經提到過開發中充滿了矛盾,一些原則本身就是彼此矛盾的,需要不斷在這些矛盾中尋求折中、平衡。這裡給出一個源自實際的簡單例子,希望能給大家一點啟示,只是不知道是否貼切(說明:用C++語言描述,T為每個資料型別)。
在定義某個類的介面時,需要定義兩個相關變數a和b的getter/setter。為了使介面儘量精簡,我們採用第一種方法,用一對getter/setter來處理:
getAB(T* pa, T* pb);
setAB(T a, T b);
但是,如果有時只想對其中一個變數進行存取時,getAB/setAB就需要額外的工作,client方的程式碼就會很累贅。
為了獲取a的值,不得不定義一個額外的變數b:
T a, b;
getAB(&a, &b);
cout << a; // only get a
為了設定a的值而保留b的值,不得不額外呼叫getAB:
T a, b;
getAB(&a, &b);
a = 10;
setAB(a, b); // only set a
為此,我們採用第二種方法,將之拆成兩對函式:
T getA();
T getB();
void setA(T a);
setB(T b);
這樣,介面就一下擴充套件了一倍。但是,事情並未就此結束。有時,像getAB/setAB這樣的方式並非只起到了簡化介面的作用。在呼叫setAB的時候,我們可以從a和b相關的角度來考察a和b的合法性,比如:a,b代表某個值域的上下限,那麼假定如果a > b時,設定就不合理,就應該拒絕。而這種合法性檢查用第二種方法實現的時候就不是那麼順利了,粗看起來程式碼應該如下:
void setA(T a)
{
if (a > m_b)
return; // error
else
m_a = a;
}
void setB(T b)
{
if (b < m_a)
return; // error
else
m_b = b;
}
如果只是設定a、b中的一個值,倒不會有任何麻煩,這種方法完全勝任。但是,如果同時設定呢?暫且不考慮a、b的初值應該如何取,比如某次對a、b的設定使a、b分別等於5、10,而再次試圖重設a、b為15、20時,問題就產生了:
setA(15);
setB(20);
結果變成了a = 5, b = 20(completely error)。
如果要得到正確結果,則需要顛倒呼叫setA和setB的次序。但是,如果a、b要分別設成1、6呢?亦即,為了保證成功設定,client程式碼需要十分小心,不同情況,採用不同的呼叫約定。對於上述情況,用第二種方法很難做到正確的合法性檢查,因為函式的signature決定了它無法得知相關的另一個值,從而不能做出正確判斷。
所以,事情的演變過程就是:
為了使介面精簡,我們選擇方法一;
為了不增加額外的客戶程式碼,我們選擇方法二;
為了進行合法性檢查,我們又不得不選擇方法一。
這裡總共出現了兩種方法,三個原則(“為了……”)。
而當我們最終決定選擇方法二時,還是有可能揹負著“增加額外的客戶程式碼”這樣的罪名。而如果你確實不想如此,或許你會將兩種方法結合使用,即把getA/setA,getB/setB,getAB/setAB統統定義為介面。可是,你又可能會被人指責為“介面混亂”,而且對於setA/setB而言,合法性檢查仍然是個問題。
結論:在有多種方法可供選擇時,存在不同的原則(選擇依據),針對實際的情況,我們需要作出決定。這種決定往往不會做到滿足所有原則,但一般它應該是最大限度的適合大多數情形。如果,實際的情況不能足以使你作出很肯定的判斷,那麼,恐怕只有習慣和直覺可以影響你的決定了。只是,或許以後你還會修改你的決定。
ps:為了說明方便,所以這裡選用了一個極為簡單的例子。坦白講,可能有誇大之嫌。實際情況下,對於這樣的“getter/setter”問題,你多半不會像文中說得那樣處於如此為難的境地,除非你是個完美主義者。你可以很快作出決定,因為即使無法滿足某條原則,其代價也不會很高。否則,那些軟體開發人員,每天就不用寫幾行程式碼了,而且會深陷於矛盾的痛苦之中。但是,在這樣細微的地方都會存在矛盾,可以想見,用“矛盾重重”來形容軟體開發過程,可能是不算誇張的。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752043/viewspace-992790/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 擼一個簡單的MVVM例子MVVM
- C++ Boost 之Python(一個簡單的例子) (轉)C++Python
- 一個最簡單的 Github workflow 例子Github
- 一個簡單的觀察者模式例子模式
- 一個簡單的Ajax請求例子
- 用java實現一個簡單的序列化的例子(轉)Java
- 用java實現一個簡單的序列化的例子 (轉)Java
- 關於Java的RMI程式設計的一個簡單的例子 (轉)Java程式設計
- 在 Golang 中實現一個簡單的Http中介軟體GolangHTTP
- 一個簡單的netty通訊的例子Netty
- WebRTC:一個視訊聊天的簡單例子Web單例
- 一個簡單的例子教會您使用javapJava
- 一個簡單的spring-boot例子Springboot
- 一個簡單的例子帶你理解HashmapHashMap
- 一個閉包函式的簡單例子函式單例
- Java多型的一個簡單入門的例子Java多型
- spring攔截器的一個簡單例子Spring單例
- 直播平臺軟體開發,一個簡單的Android登入實現demoAndroid
- JUnit概述及一個簡單例子單例
- 軟體開發中的專案管理(轉)專案管理
- 軟體專案的鐵三角模型:軟體質量與快速開發的矛盾 - Richard模型
- golang開發一個簡單的grpcGolangRPC
- 想作一個很簡單的HA cluster軟體
- 共享軟體中註冊部分的簡單實現(轉)
- Spring-Context之一:一個簡單的例子SpringContext
- 一個簡單的oracle函式返回陣列的例子Oracle函式陣列
- php mysql 一個查詢優化的簡單例子PHPMySql優化單例
- linux c 一個autotools的最簡單例子Linux單例
- 轉一篇OpenSSL的例子:簡單的TLS伺服器TLS伺服器
- 關於多個開發中心開發同一軟體的配置管理(轉)
- 行軟體開發中的專案管理 (轉)專案管理
- 對軟體開發的一點心得體會 (轉)
- 如何設計一個簡單的訊息中介軟體
- 【轉載】軟體開發模式簡介模式
- 一個用VB編寫的監控別人上網的軟體例子 (轉)
- XPATH的簡單例子單例
- 一個關於SQL隱碼攻擊的簡單例子SQL單例
- Unity如何連線伺服器: 一個簡單的例子Unity伺服器