英文:
It''s never a good idea for a public class to expose fields directly, but why it is less harmful if the fields are immutable?
问题
以下是翻译好的内容:
我正在阅读《Effective Java》第14条 - 在公共类中使用访问方法,而不是公共字段。书中提到:虽然公共类直接暴露字段从来都不是一个好主意,但如果字段是不可变的,那么它的危害就较小。
我的问题是,为什么如果字段是不可变的,那么它的危害较小呢?你能给出一个现实生活中的例子来证明吗?以下是书中的代码示例。
// 通过访问方法和修改器封装数据
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; }
}
虽然公共类直接暴露字段从来都不是一个好主意,但如果字段是不可变的,那么它的危害就较小。
// 具有暴露的不可变字段的公共类 - 有问题
public final class Time {
public final int hour;
public final int minute;
public Time(int hour, int minute) {
this.hour = hour;
this.minute = minute;
}
}
英文:
I'm reading an article from Effective Java Item 14 - In public classes, use accessor methods, not public fields. In the book it says: While it’s never a good idea for a public class to expose fields directly, it is less harmful if the fields are immutable.
My question is why it's less harmful if the fields are immutable? Could you give a real-life example to justify? Here is the code example in the book.
/ 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 void setX(double x) { this.x = x; }
public double getY() { return y; }
public void setY(double y) { this.y = y; }
}
While it’s never a good idea for a public class to expose fields directly, it is less harmful if the fields are immutable.
// Public class with exposed immutable fields - questionable
public final class Time {
public final int hour;
public final int minute;
public Time(int hour, int minute) {
this.hour = hour;
this.minute = minute;
}
}
答案1
得分: 0
如果您的对象仅具有不可变字段,则很大程度上可以将该对象视为不可变的。
这意味着:在创建时,该对象将永远不会更改其内容。因此,您可以从任意数量的位置引用该对象。没有其他对象需要担心相应的数据会在某些其他代码执行某些操作时发生神奇变化。
实际上,直接字段访问和提供setter方法之间的区别并不重要!唯一产生巨大概念差异的是:可变与不可变。
而且请注意:理想情况下,类的公共方法为您提供客户端代码可以使用的行为!
英文:
If your object has solely immutable fields, most likely that object itself can be regarded immutable.
Which means: upon creation, that object will never change its content. Thus you can reference to that object from any number of places. And no other object needs to worry that the corresponding data will magically change, because some other code did something.
Essentially, the difference between direct field access and providing a setter method isn't what matters! The only thing that makes a huge conceptual difference: mutable vs immutable.
And note: ideally, the public methods of a class provide you behavior that client code can use!
答案2
得分: 0
这在下一句中得到了清楚的解释,然后他举了一个例子。我有第二版,也许你有第一版,而它缺失了吗?
尽管对于公共类直接暴露字段从未是一个好主意,但如果这些字段是不可变的,那么它就不会那么有害。您不能更改这种类的表示,而不改变其API,也不能在读取字段时执行辅助操作,但您可以强制执行不变量。(我强调)
书中提供的强制执行不变量的示例:
例如,这个类确保每个实例表示一个有效的时间:
// 公共类,暴露了不可变字段 - 有问题的
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;
}
// 其余部分省略
}
英文:
It's explained clearly in the following sentence and then he gives an example. I have the second edition, maybe you have the first edition and it's missing from it?
> While it’s never a good idea for a public class to expose fields directly, it is
less harmful if the fields are immutable. You can’t change the representation of
such a class without changing its API, and you can’t take auxiliary actions when a
field is read, but you can enforce invariants. (emphasis mine)
The enforcing invariants example given in the book:
> For example, this class guarantees
that each instance represents a valid time:
// 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
}
答案3
得分: -1
// 公共类具有暴露的不可变字段 - 有问题
public final class Time {
public final int hour;
public final int minute;
public Time(int hour, int minute) {
this.hour = hour;
this.minute = minute;
}
}
使用上述代码,创建上述类的对象的类必须了解这些字段。这引入了紧密耦合。
另外,如果您在对象声明时使用接口进行编码,所有实现都将实现这些方法,开发人员可以更轻松地通过方法访问值,并且每个实现都可以使用这些类级别的变量并根据实现细节进行返回。
英文:
// Public class with exposed immutable fields - questionable
public final class Time {
public final int hour;
public final int minute;
public Time(int hour, int minute) {
this.hour = hour;
this.minute = minute;
}
}
With the above code, the Class which is creating the object of the above class must have knowledge about the fields. This introduces a tight coupling.
Also, if you are coding to interfaces when the object is declared using the interface name all the implementations will implement the methods and it will be easier for the developer to access the value using methods and every implementation can use these class level variables and return as per the implementation details.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论