经验丰富的 Java 开发人员会在何时以及何时不应用代码库中的 getter 和 setter 以及 accessor 办法的状况下进行查看。
Java Getter 设置器
为什么咱们将实例变量设为公有?咱们不心愿其余类依赖它们。而且,它须要灵活性,能够一时衰亡或一时冲动地更改变量的类型或实现。那么,为什么程序员会主动将 getter 和 setter 增加到其对象中,从而像公开一样公开其公有变量?
存取器办法
拜访器(也称为 getter 和 setter)是使您能够读写对象的实例变量的值的办法。
public class AccessorExample {
private String attribute;
public String getAttribute() {
return attribute;
}
public void setAttribute(String attribute) {
this.attribute = attribute;
}
}
为什么要应用存取器?
实际上,有很多充沛的理由思考应用拜访器,而不是间接公开类的字段。
Getter 和 Setter 使 API 更加稳固。例如,思考一个类中的公共字段,其余类能够拜访该字段。稍后,如果咱们想在获取和设置变量时增加任何额定的逻辑,这将影响应用该 API 的现有客户端。因而,对此公共字段进行的任何更改都将要求对援用它的每个类进行更改。另一方面,应用拜访器办法,能够轻松增加一些逻辑,例如缓存某些数据或提早初始化。
拜访器办法还容许咱们在新值与先前值不同的状况下触发属性更改事件。
应用 setter 设置值的另一个长处是,在设置值时,咱们能够应用该办法保留不变式或执行一些非凡解决。
所有这些对于应用 accessor 办法获取值的类都是无缝的。
我应该为我的所有字段都应用拜访器办法吗?
对于包公有或公有嵌套类,能够将字段申明为公共字段。与拜访器办法相比,在类定义中以及在应用它的客户端代码中,与拜访器办法相比,裸露这些类中的字段所产生的视觉凌乱更少。
如果一个类是程序包公有的或公有嵌套的类,则公开其数据字段并没有天生的谬误 - 假如它们在形容该类提供的形象方面做得足够好。
此类代码仅限于申明该类的包,而客户端代码则绑定到一个类的外部示意。咱们能够更改它,而无需批改该程序包之外的任何代码。而且,在公有嵌套类的状况下,更改的范畴进一步限于关闭类。
应用公共字段的设计的另一个示例是 JavaSpace 条目对象。肯·阿诺德(Ken Arnold)形容了他们决定应用此处的 get 和 set 办法将这些字段公开而不是公有的过程。
当初,这有时使人们感到不难受,因为有人通知他们不要应用公共场所,并且公共场所不好。规定有其起因。专用数据规定的起因不适用于这种非凡状况。这是该规定的常见例外。我还通知人们不要在其对象中搁置公共字段,然而存在例外。这是该规定的一个例外,因为仅说它是一个字段就更简略,更平安。咱们坐下来问:为什么是这样的规定?是否实用?在这种状况下,不是。
专用字段 + 公共拜访器 == 封装
思考上面的示例:
public class A {
public int a;
}
通常,这被认为是不良的编码实际,因为它违反了封装。另一种办法是:
public class A {
private int a;
public void setA(int a) {
this.a =a;
}
public int getA() {
return this.a;
}
}
有人认为这封装了属性。当初,这真的是封装吗?
事实是,getter / setter 与封装无关。在这里,数据没有比在公共畛域中更多地被暗藏或封装。其余对象依然对类的外部常识有深刻的理解。对类所做的更改可能会泛滥,并在隶属类中强制执行更改。以这种形式,getter 和 setter 通常会毁坏封装。真正封装良好的类没有设置办法,最好也没有设置办法。该类应该负责应用其数据计算某些内容,而后返回后果,而不是向类询问一些数据而后应用它来计算某些内容。
思考上面的示例:
public class Screens {
private Map screens = new HashMap();
public Map getScreens() {
return screens;
}
public void setScreens(Map screens) {
this.screens = screens;
}
// remaining code here
}
如果须要获取特定屏幕,请编写如下代码:
Screen s = (Screen)screens.get(screenId);
这里有一些值得注意的事件…
客户端须要从 Map 中获取一个 Object 并将其强制转换为正确的类型。而且,最蹩脚的是,地图的任何客户端都有权将其革除,而这通常不是咱们通常想要的。
雷同逻辑的另一种实现是:
public class Screens {
private Map screens = new HashMap();
public Screen getById(String id) {
return (Screen) screens.get(id);
}
// remaining code here
}
在此,Map 实例和边界处的接口(Map)被暗藏。
吸气剂和二传手被适度应用
创立公有字段,而后应用 IDE 为所有这些字段主动生成 getter 和 setter 简直和应用 public 字段一样蹩脚。
适度应用的起因之一是,在 IDE 中,只需单击几下即可创立这些拜访器。齐全无意义的 getter / setter 代码有时比类中的实在逻辑还要长,即便您不想这样做,您也会屡次浏览这些函数。
所有字段都应放弃公有状态,然而,设置器仅应在有意义的状况下放弃公有状态,从而使该对象不可变。增加不必要的吸气剂会揭示内部结构,这是减少耦合的机会。为了防止这种状况,每次增加拜访器之前,咱们都应该剖析是否能够封装行为。
让咱们再举一个例子:
public class Money {
private double amount;
public double getAmount() {
return amount;
}
public void setAmount(double amount) {
this.amount = amount;
}
//client
Money pocketMoney = new Money();
pocketMoney.setAmount(15d);
double amount = pocketMoney.getAmount(); // we know its double
pocketMoney.setAmount(amount + 10d);
}
根据上述逻辑,当前,如果咱们假如 double 不是要应用的正确类型,而应该应用 BigDecimal,那么应用该类的现有客户端也会中断。
让咱们重组下面的示例:
public class Money {
private BigDecimal amount;
public Money(String amount) {
this.amount = new BigDecimal(amount);
}
public void add(Money toAdd) {
amount = amount.add(toAdd.amount);
}
// client
Money balance1 = new Money(“10.0”);
Money balance2 = new Money(“6.0”);
balance1.add(balance2);
}
当初,班级不再要求价值,而是有责任减少本人的价值。应用这种办法,未来对任何其余数据类型的更改申请都不须要更改客户端代码。
论断
与应用公共字段相比,应用拜访器来限度对字段变量的间接拜访更为可取,然而,使每个字段都应用 getter 和 setter 会显得过大。不过,这也取决于状况。有时您只想要一个哑数据对象。拜访器应增加到真正须要它们的字段中。一个类应该暴露出恰好应用其状态的更大行为,而不是裸露由其余类操纵的状态存储库。
参考:《2020 最新 Java 根底精讲视频教程和学习路线!》
链接:https://blog.csdn.net/weixin_…