標籤:java effective
模組設計是否良好,有個重要的因素在於,相對外部模組是否隱藏內部資料以及實現細節。
設計良好的模組會隱藏實現細節,並將API與其實現隔離開來。
模組之間通過API進行通訊,對於內部工作情況互不可見。
即,封裝(encapsulation)——軟體設計的基本原則之一。
為什麼要封裝?
通過封裝可以有效地接觸各個模組之間的耦合關係,使這些模組可以獨立地開發、測試、最佳化、使用、理解和修改。
即:
·可以增加開發效率,模組可以並行開發。
·封裝可以減輕維護的負擔,可以更有效進行最佳化,且不會影響其他模組的正確性。
·提高了軟體的可重用性,模組在其他環境中也可以被使用。
(PS:回想我自己以前用php寫網站時根本沒有這些概念也不影響開發工作。當時覺得沒什麼,因為是我一個人寫的,再加上後來也沒有再擴充,於是沒有了種種體會。)
可以通過存取控制保證封裝。
一個實體的可訪問性是通過實體聲明所在的位置和存取修飾詞共同決定的。
建議<儘可能地使每個類或者成員不被外界訪問>。
對於頂層的類和介面只有兩種存取層級:包級私人和公有。
更小的可訪問性代表更小的相容性,在以後發行的版本中可以放心對其進行修改。
如果是公有的,則需要一直考慮客戶的行為。(PS:如果一個頂層類只是在某一個類的內部被用到,則可以聲明為私人靜態內部類。)
比如這樣一個類,這樣做在以後的版本中便無法改變表示方式,而且無法加入任何約束:
class Point {public double x;public double y;}
於是正如很多人的習慣那樣,對於公有類用公有的存取方法替代公有field以保證資料在類內部的靈活性:
class Point {private double x;private double y;public Point(double x, double y) {this.x = x;this.y = y;}public double getX() {return x;}public double getY() {return y;}public void setX(double x) {this.x = x;}public void setY(double y) {this.y = y;}}
(PS:當然,有些常見的類並沒有遵守這一規則比如java.awt.Point、java.awt.Dimension。但原作者也明確指出這些類不值得效仿。)
如果一個field只能是公有的,且允許將其聲明為final,則危害能少一些。
我們仍然可以通過公有的存取方法訪問該field。
但不能用公有的setter,而是通過構造器加入約束:
public final class Time {private static final int HOURS_PER_DAY = 24;private static final int MINUTES_PER_HOUR = 60;public final int hour;public final int minute;public Time(int hour, int minute) {if (hour < 0 || hour >= HOURS_PER_DAY)throw new IllegalArgumentException("Hour: " + hour);if (minute < 0 || minute >= MINUTES_PER_HOUR)throw new IllegalArgumentException("Min: " + minute);this.hour = hour;this.minute = minute;}// Remainder omitted}
對於成員(field,method,嵌套類,嵌套介面)有4種存取層級:
·private
·package-private(default)
·protected
·public
上面是按可訪問性的遞增順序羅列。
當設計了類的公有API後,我們將所有成員都變成私人。
然後發現同一個包內的另一個類也需要訪問這個成員,於是便修改存取層級。如果這種事情經常發生則應該檢查設計是否合理。
雖然package和private層級的成員都是類實現的一部分,不會影響匯出的API。但,該類實現了Serializable時則另當別論。
如果使用protected修飾,則需要注意,該成員時匯出的API的一部分。
另外,執行個體field盡量不要設定為公有。如果一個field不是final或者是一個指向可變對象的final field,公有的存取層級會破壞該field的不可變性,它已不是一個內部的資料表示,而且非安全執行緒。
當然,這對於長度!=0的數組也是一樣的。
如果需要將某數組聲明為公有,可以嘗試以下方式:
private static final Thing[] PRIVATE_VALUES = {...};public static final List<Thing> VALUES = Collections.unmodifiableList(Arrays.asList(PRIVATE_VALUES));
或者可以使用clone,每次都拷貝一個數組:
private static final Thing[] PRIVATE_VALUES = {...};public static final Thing[] values(){ return PRIVATE_VALUES.clone();}
本文出自 “Alvez. 99.9% 0B/s” 部落格,請務必保留此出處http://runtime.blog.51cto.com/7711135/1439747