在封装中,我们的想法是通过将其声明为私有来隐藏您的类正在对变量执行的操作,从而实现OCP。但那么为什么你会添加getter和setter,然后打开你的变量进行修改?
为什么要彻底解决将变量设置为私有的问题,然后在其上添加公共setter?这似乎并不是非常严格的限制,这是封装的一个想法。
答案 0 :(得分:4)
打开您的变量进行修改
在开放式原则中,“开放”一词意味着完全不同的东西。
这意味着类的源代码已关闭以进行修改,但结果类工件已打开,可通过扩展进行进一步修改。 open 和 closed 都不会引用该类的实例的任何方面。
另一方面,我从一个稍微不同的角度来看待你对吸气剂/安装者的批评:他们添加了大量的样板,只是为了将你的整体设计恢复到几乎与公共领域的类相同的东西。 / p>
在一些不那么常见的案例中,仍然需要给予getter / setter。对于属于库的公共API的类,以及通常通过setter配置的具有一些非平凡行为的类,都是如此。
对于纯数据类,getter / setter主要是由过时框架的要求强制进入它们,这些框架拒绝使用公共字段。 Spring,Hibernate和Jackson是最先进的框架的例子,不强迫它。
答案 1 :(得分:3)
你在这里 假设这是我的实例变量
private double x;
通过使用Setters,您可以对值进行自己的验证,将其设置为实例变量。
public void setX(double x)
{
if (x <= 0)
System.out.println("Wrong value, value should be greater than 0");
else
this.x = x;
}
通过使用Getters,您将能够以您希望用户看到的格式返回数据。
public double getX()
{
return Double.valueOf(String.format("%.3f", this.x));
}
答案 2 :(得分:2)
直接设置变量可以控制外部代码,如
class A {
public String a;
}
A a = new A();
a.a = "bad value which will cause code fail"
但是对于getter和setter来说,
class A {
private String a;
public void setA(String a) {
if(! "some bad value".equals(a) ) {
this.a = a;
}
}
}
因此,使用getter和setter将为我们的类实例提供控件,而不是其他可能的坏类。
答案 3 :(得分:2)
封装是关于隐藏实现细节。
您的getter和setter方法是您所在类的已发布API的一部分,并提供了一种明确定义的方式来查看正在发生的事情。
在内部,您可以删除所有实现并执行完全不同的操作,但通过维护相同的set和get方法,此更改对于其他所有类都是不可见的。
API应该是关于使用它的人想要做的事情,而不是关于你如何做的内部细节。
例如,如果您有一个连接到服务器的类并且具有包含名称和端口的字符串并且现在公开该字符串,那么您将与该字符串绑定。
如果将来你想分开它并分别存储名称和端口,你就不能这样做,因为人们可能正在阅读或直接设置该字符串 - 而且你会破坏所有人的代码。
或者更糟糕的是,假设你保存的内容相同 - 但你需要知道它何时发生变化。这是不可能的(实际上有很多hacky方式,比如存储你上次查看的字符串,检查更改,或者运行一个线程来查找更改等等,所有这些方法都是hacky和低效的)
答案 4 :(得分:1)
通过设置者和吸气剂,你可以
答案 5 :(得分:1)
一般来说,你应该单独设计一个类的接口,即你希望你的类如何被使用,从它的实现,即它如何工作。通过这样做,可能会发生一些方法最终只是设置或获取属性的值。
但是,只有在有意义而不是一般方法时才应该这样做。
真正没有任何意义的是只有私有属性的类,每个属性的setter / getter公共方法,没有其他方法。在某些情况下,您确实需要将一些值移动到一起而没有任何特定的逻辑来绑定它们;在这种情况下,您应该定义一个只包含公共属性而没有方法的类,除了可能的构造函数。
答案 6 :(得分:1)
你绝对正确地向每个违反封装和OCP的私人成员公开添加setter / getters。
为了解释悖论,OCP需要一些上下文(即关闭相对于什么?)。在类设计级别,OCP意味着如果您更改(私有)实现细节,则不得更改(公共部分)类的客户。相对于使用封闭(公共)接口的客户端,类的私有部分可以更改。
为每个私有变量添加getter / setter都会违反OCP。这与将每个私有属性设为公共属性相同(除了其他一些答案提到的验证方面,但在我看来这些并不是重点)。有关错误原因的更多说明,请参阅Why getter and setter methods are evil。
不是基于实现细节(getter和setter)设计方法,而是尝试将类的公共接口视为一组&#34; services&#34;或者&#34;责任&#34;该类提供给系统。如果可能,这些服务应隐藏实现细节。想想该类的客户将如何使用它。请参阅Responsibility-driven design中的详情。
至于吸气者和制定者,他们并不总是坏事。在添加它们之前,请三思而后行公共方法是对您支持服务的类客户的一种承诺(如果您更改公共接口,使用该类的客户将会中断)。如果您在公共界面中显示它们,您可能会更难以更改类的详细信息。
当您返回(通过获取)对作为实现细节一部分的对象的引用时,需要考虑另一个角度。获得该引用的客户端然后可以操纵该对象(获取显示的实现细节)。例如,Student.admissionDate:Date
有一个getter,它返回对Date的引用。 Student类的客户可以获取日期并进行更改。为避免这种情况,getter应返回对象的克隆。在Java中,它将是return (Date)admissionDate.clone()