Skip to content

Latest commit

 

History

History
70 lines (53 loc) · 3.27 KB

第16条:要在共有类中使用访问方法而非公有域 2f58f7b42eb74c47bc1cb66e71129e83.md

File metadata and controls

70 lines (53 loc) · 3.27 KB

第16条:要在共有类中使用访问方法而非公有域

有时候,可能需要编写一些退化的类,它们没有什么作用,只是用来集中实例域:

public class Point {
    public double x;
    public double y;
}

由于这种数据域是可以被直接访问的,这些类没有提供封装。如果不改变API,就无法改变它的数据表示法,也无法强加任何约束条件;当域被访问的时候,无法采取任何辅助的行动。坚持面向对象编程的程序员对这种类深恶痛绝,认为应该用包含私有域的公有方法(getter)的类代替。对于可变类来说,应该用拥有设值得方法(setter)得类代替。

public 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 void setX(double x) {
        this.x = x;
    }

    public double getY() {
        return y;
    }

    public void setY(double y) {
        this.y = y;
    }
}

毫无疑问,说到共有类得时候,坚持面向对象编程思想得看法是正确的:如果类可以在它所在的包之外进行访问,那就提供访问方法,以保留将来改变类的内部表示法的灵活性。如果公有类暴露了它的数据域,要像在将来改变其内部表示法是不可能的,因为共有类的客户端代码已经遍布各处了。

然而,如果类是包级私有的,或则是私有的嵌套类,直接暴露它的数据域并没有本质的错误——假设这些数据域确实描述了该类所提供的抽象。无论是在类的定义中,还是在使用该类的客户端中代码中,这种访问方法的做法更不容易产生视觉混淆。虽然客户端代码与该类的内部表示法紧密相连,但是这些代码被限定在包含该类的包中。如果有必要,也可以不改变包之外的任何代码,而只改变内部数据表示法。在私有嵌套类的情况下,改变的作用访问被进一步限制在外围类中。

让共有类直接暴露域虽然从来都不是种好的方法,但是如果域是不可变的,这种做法的危害就相对较小一些。如果不改变类的API,就无法改变这种类的表示法,当域被读取的时候,你也无法采取辅助的行动,但是可以强加约束条件。例如,这个类确保了每个实例都表示一个有效的时间:

public class Time {
    private static final int HOURS_PRE_DAY = 24;
    private static final int MINUTES_PRE_HOUR = 60;

    public final int hour;
    public final int minute;

    public Time(int hour, int minute){
        if (hour < 0 || hour > HOURS_PRE_DAY){
            throw new IllegalArgumentException("hour: " + hour);
        }
        if (minute < 0 || minute > MINUTES_PRE_HOUR){
            throw new IllegalArgumentException("minute: " + minute);
        }
        
        this.hour = hour;
        this.minute = minute;
    }
}

简而言之,共有类永远都不应该暴露可变的域。虽然还是有问题,但是让公有类暴露不可变的域,其危害相对来说较小。但是有时候会需要用包级私有或则私有的嵌套类来暴露域,无论这个类是可变的还是不可变的。