Effective Java 第三版——16.在公共類中使用訪問方法而不是公共屬性

Tips
《Effective Java, Third Edition》一書英文版已經出版,這本書的第二版想必不少人都讀過,號稱Java四大名著之一,不過第二版2009年出版,到如今已經將近8年的時間,但隨着Java 6,7,8,甚至9的發佈,Java語言發生了深入的變化。
在這裏第一時間翻譯成中文版。供你們學習分享之用。java

Effective Java, Third Edition

16. 在公共類中使用訪問方法而不是公共屬性

有時候,你可能會試圖寫一些退化的類(degenerate classes),除了集中實例屬性以外別無用處:程序員

// Degenerate classes like this should not be public!
class Point {
    public double x;
    public double y;
}

因爲這些類的數據屬性能夠直接被訪問,所以這些類不提供封裝的好處(條目 15)。 若是不更改API,則沒法更改其表示形式,沒法強制執行不變量,而且在訪問屬性時沒法執行輔助操做。 堅持面向對象的程序員以爲這樣的類是厭惡的,應該被具備私有屬性和公共訪問方法的類(getter)所取代,而對於可變類來講,它們應該被替換爲setter設值方法:性能

// Encapsulation of data by accessor methods and mutators
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; }

}

固然,對於公共類來講,堅持面向對象是正確的:若是一個類在其包以外是可訪問的,則提供訪問方法來保留更改類內部表示的靈活性。若是一個公共類暴露其數據屬性,那麼之後更改其表示形式基本上沒有可能,由於客戶端代碼能夠散佈在不少地方。學習

可是,若是一個類是包級私有的,或者是一個私有的內部類,那麼暴露它的數據屬性就沒有什麼本質上的錯誤——假設它們提供足夠描述該類提供的抽象。在類定義和使用它的客戶端代碼中,這種方法比訪問方法產生更少的視覺混亂。 雖然客戶端代碼綁定到類的內部表示,可是這些代碼僅限於包含該類的包。 若是類的內部表示是可取的,能夠在不觸碰包外的任何代碼的狀況下進行更改。 在私有內部類的狀況下,更改做用範圍進一步限制在封閉類中。this

Java平臺類庫中的幾個類違反了公共類不該直接暴露屬性的建議。 着名的例子包括java.awt包中的PointDimension類。 這些類別應該被視爲警示性的示例,而不是模仿的例子。 如條目 67所述,暴露Dimension的內部結構的決定是一個嚴重的性能問題,這個問題在今天仍然存在。翻譯

雖然公共類直接暴露屬性並非一個好主意,可是若是屬性是不可變的,那麼危害就不那麼大了。當一個屬性是隻讀的時候,除了更改類的API外,你不能改變類的內部表示形式,也不能採起一些輔助的行爲,可是能夠增強不變性。例如,下面的例子中保證每一個實例表示一個有效的時間:code

// Public class with exposed immutable fields - questionable

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
}

總之,公共類不該該暴露可變屬性。 公共累暴露不可變屬性的危害雖然仍然存在問題,但其危害較小。 然而,有時須要包級私有或私有內部類來暴露屬性,不管此類是不是可變的。對象

相關文章
相關標籤/搜索