What is the point of getters and setters?
Possible Duplicate:
Why use getters and setters?
我读过有关
1 2 3 4 5 6 7 | public int getX(){ return x; } public void setX(int x){ this.x = x; } |
但是有什么区别呢
1 | ...(shape.x)... // basically getX() |
和
1 | shape.x = 90; // basically setX() |
如果二传手和getter更好,你能给我解释一下会出现什么实际问题吗?
多种原因:
如果你允许像
形状:x=90
然后您就不能在将来添加任何逻辑来验证数据。
如果x不能小于100,就不能这样做,但是如果有
1 2 3 4 5 | public void setShapeValue(int shapeValue){ if(shapeValue < 100){ //do something here like throw exception. } } |
- 不能添加类似copy-on-write逻辑的内容(请参阅copyonwritearraylist)
- 另一个原因是访问类外部的字段时,您必须将它们标记为公共、受保护或默认,这样您就失去了控制。当数据非常内部的破类封装和一般的OOPS方法。
但是对于常量来说
1 |
您将允许字段访问,因为它们不能被更改,例如变量,您将把它们与getter、setter放在一起。
- 另一种情况是,当您希望类不可变时,如果您允许字段访问,那么您将破坏类的不可变性,因为值可以更改。但是如果你用getter和no setter仔细设计你的类,你就可以保持不变。
但是在这种情况下,您必须小心getter方法,以确保不给出对象的引用(在类中有对象作为实例的情况下)。
我们可以使用getter和setter在任何包中使用私有变量。
使用getter和setter函数允许约束和封装。假设x是半径。shape.x=-10没有什么意义。此外,如果有人试图设置非法值,您可以打印错误、设置默认值或不执行任何操作。
最好的做法是将成员变量设为私有,这样就不能由使用它们的程序直接修改它们。
变异函数包封
很多人提到过封装实现的细节,这对我来说是在类中使用getter和setter的最大原因。有了这一点,您还可以获得许多其他好处,包括可以根据一时的兴致放弃并替换实现,而无需接触使用类的每一段代码。在一个小项目中,这不是一个很大的好处,但是如果您的代码最终成为一个使用良好(内部或公共)的库,那么它可能是一个巨大的好处。
一个具体的例子:数学中的复数。有些语言将它们作为一种语言或框架功能,而另一些则没有。我将使用一个可变类作为示例,但它也可以很容易地不可变。
复数可以用实部和虚部写在
然而,在某些情况下,很容易解释极性形式
您还可以公开方法,如
这两种形式是可以互换的;您可以很容易地从一种形式转换到另一种形式,因此类用于内部存储的哪种形式与该类的使用者无关。然而,消费者可以使用任何一种形式。如果您选择a+bi形式作为内部表示,并使用字段而不是getter和setter公开这一点,那么您不仅要强制类使用者使用该形式,而且以后也不能轻易地改变主意,并用re^(iθ)替换内部表示,因为这更容易在特定的sc中实现。埃纳里奥您坚持使用您定义的公共API,它要求使用特定字段名公开真实和虚拟部分。
下面的例子可以理解用户getter和setter的另一个好理由。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
getter和setter的要点是,只有它们被用来访问它们正在获取或设置的私有变量。通过这种方式,您可以提供封装,稍后重构或修改代码将更容易。
假设您使用名称而不是getter。然后,如果您想添加一些类似于默认值的内容(如果以前没有设置默认名称,那么就说默认名称是"guest"),那么您必须同时修改getter和say name函数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
getter和setter不需要从get和set开始——它们只是普通的成员函数。但这是一个惯例。(特别是如果使用Java bean)
对于getter和setter,我能想到的最好的原因之一是类的API的持久性。在类似于Python的语言中,您可以通过成员的名称访问成员,并在以后将其切换到方法。因为函数一旦在Java中访问成员,它的行为就不同于Java中的成员。限制其作用域以后会破坏客户端。
通过提供getter和setter,程序员可以灵活地自由修改成员和行为,只要遵守公共API所描述的契约。
最初,getter/setter模式是由
- 隐藏属性的内部表示形式
这是您问题的最佳答案,为什么要使用getter和setter?
假设你找到了一个图书馆,它能更好地处理你在自己班上所做的事情(你的屁股)。在这一点上要做的自然的事情是使您的类成为该库的包装器接口。它仍然有一个"x"的概念,您的客户机代码需要获取或设置它。当然,此时您几乎必须编写访问函数。
如果您忽略了使用访问函数,并且让客户机代码直接访问yourclass.x,那么现在您必须重写所有曾经接触过您rclass.x的客户机代码。但是,如果您从一开始就使用yourclass.getx()和yourclass.setx(),那么您只需要重写自己的类。
编程的一个关键概念,尤其是面向对象编程,是隐藏实现细节,这样其他类或模块中的代码就不会直接使用它们。这样,如果您更改了实现细节(如上面的示例中所示),客户机代码就不知道区别,也不需要修改。尽管您的客户机代码知道,"x"可能是一个变量,也可能是一个动态计算的值。
这过于简单化了,并没有涵盖所有隐藏实现是有益的场景,但这是最明显的例子。隐藏实现细节的概念现在已经与OOP紧密联系在一起了,但是您可以在OOP出现之前的几十年中找到关于它的讨论。它可以追溯到软件开发的核心概念之一,即取一个大的模糊问题,将其分为小的、定义明确的、易于解决的问题。访问函数有助于使小的子任务保持分离和定义良好:类对彼此内部的了解越少越好。
在回答之前,我们必须先知道一些事情…!"JavaBeansJavaBeans是具有属性的Java类。出于我们的目的,将属性视为私有实例变量。因为它们是私有的,所以只有这样才能访问它们从类的外部通过类中的"方法"。更改属性值的方法称为setter方法,检索属性值的方法称为getter方法。
原因很多。这里只有一些。
因为我们使用的是面向对象的编程语言。这里我们使用数据隐藏和封装。变量不应该直接从外部世界访问(用于实现数据隐藏),因此我们将创建它private,以便
形状X
是不对的。采用getter和setter方法获取和设置x值,实现封装。
getter和setter封装类的字段,使它们只能通过其公共方法访问,并使值本身保持私有。这被认为是一个很好的OO原则。
当然,如果只是设置或返回一个值,那么它通常看起来像是冗余代码。但是,setter还允许您进行输入验证或清除。把它放在一个地方可以提高对象的数据完整性,
这是通过应用OOP的封装原理来实现的。
A language mechanism for restricting access to some of the object's components.
这意味着,必须定义类的属性和方法的可见性。共有3种常见的可见性:
- private:只有类可以查看和使用属性/方法。
- 受保护:只有类及其子类才能查看和使用属性/方法。
- 公共:每个类都可以看到和使用属性/方法。
当您声明私有/受保护的属性时,建议您创建方法来获取值(get)并更改值(set)。关于可见性的一个例子是
1 2 3 4 5 6 7 8 9 10 11 | public class ArrayList<E> { private int size; private Object[] array; public getSize() { return this.size; } public void add(E element) { //logic to add the element in the array... this.size++; } } |
在本例中,您可以看到大小值只能在类方法内部更改,并且您可以通过在代码中调用它(而不是改变它)来获取实际大小:
1 2 3 4 5 6 7 8 9 | public void someMethod() { List<String> ls = new ArrayList<String>(); //adding values ls.add("Hello"); ls.add("World"); for(int i = 0; i < ls.size(); i++) { System.out.println(ls.get(i)); } } |
我会说getter/setter和public成员都不是好的面向对象设计。它们都通过向世界公开对象数据来破坏OOP封装,而这些数据可能一开始就不应该访问对象的属性。