有時,重復(fù)來自設(shè)計中的錯誤。
讓我們看一個來自配送行業(yè)的例子。假定我們的分析揭示,一輛卡車有車型、牌照號、司機及其他一些屬性。與此類似,發(fā)運路線的屬性包括路線、卡車和司機?;谶@一理解,我們編寫了一些類。
但如果Sally打電話請病假、我們必須改換司機,事情又會怎樣呢?Truck和DeliverRoute都包含有司機。我們改變哪一個?顯然這樣
的重復(fù)很糟糕。根據(jù)底層的商業(yè)模型對其進行規(guī)范化(normalize)--卡車的底層屬性集真的應(yīng)包含司機?路線呢?又或許我們需要第三種對象,把司
機、卡車及路線結(jié)合在一起。不管最終的解決方案是什么,我們都應(yīng)避免這種不規(guī)范的數(shù)據(jù)。
當我們擁有多個互相依賴的數(shù)據(jù)元素時,會出現(xiàn)一種不那么顯而易見的不規(guī)范數(shù)據(jù)。讓我們看一個表示線段的類:
- class Line {
- public:
- Point start;
- Point end;
- double length;
- };
第一眼看上去,這個類似乎是合理的。線段顯然有起點和終點,并總是有長度(即使長度為零)。但這里有重復(fù)。長度是由起點和終點決定的:改變其中一個,長度就會變化。最好是讓長度成為計算字段:
- class Line {
- public:
- Point start;
- Point end;
- double length() { return start.distanceTo(end); }
- };
在以后的開發(fā)過程中,你可以因為性能原因而選擇違反DRY原則。這經(jīng)常會發(fā)生在你需要緩存數(shù)據(jù),以避免重復(fù)昂貴的操作時。其訣竅是使影響局部化。對DRY原則的違反沒有暴露給外界:只有類中的方法需要注意"保持行為良好"。
- class Line {
- private:
- bool changed;
- double length;
- Point start;
- Point end;
-
- public:
- void setStart(Point p) { start = p; changed = true; }
- void setEnd(Point p) { end = p; changed = true; }
-
- Point getStart(void) { return start; }
- Point getEnd(void) { return end; }
-
- double getLength() {
- if (changed) {
- length = start.distanceTo(end);
- changed = false;
- }
- return length;
- }
- };
這個例子還說明了像Java和C++這樣的面向?qū)ο笳Z言的一個重要問題。在可能的情況下,應(yīng)該總是用訪問器(accessor)函數(shù)讀寫對象的屬性 。這將使未來增加功能(比如緩存)變得更容易。
Uniform Access原則:模塊提供的所有服務(wù)都應(yīng)能通過統(tǒng)一的表示法使用,該表示法不能泄漏它們是通過存儲、還是通過計算實現(xiàn)的。