Nag*_*ran 25 oop ooad design-patterns properties accessor
我在很多地方都读过"吸气鬼和恶魔都是邪恶的".我理解为什么这样.但我不知道如何完全避免它们.Say Item是一个包含项目名称,数量,价格等信息的类......而ItemList是一个类,它有一个Items列表.要找到总计:
int grandTotal()
{
int total = 0;
for (Item item: itemList)
total += item.getPrice();
return total;
}
在上面的例子中,如何避免getPrice()?Item类提供了getName,setName等....
我该如何避免它们?
Jon*_*and 41
getter和setter非常适合配置或确定类的配置,或从模型中检索数据
获得物品的价格是一个完全合理的使用吸气剂.这是需要可用的数据,可能需要特别考虑,通过向设置器添加验证或清理来保护数据.
你也可以提供没有setter的getter.他们没有必须成对出现.
有时,对象依赖于永远不会暴露的内部属性.例如,迭代器和内部集合.公开内部收集可能会产生极大的负面和意外后果.
另外,例如,假设您正在通过某些HttpURLConnection进行通信.为您的HttpURLConnection公开setter意味着如果在等待接收数据时更改连接,您可能会得到非常奇怪的状态.此连接应该在实例化时创建或在内部完全管理.
如果您拥有公开的所有意图和目的的数据,但需要进行管理:使用getter和setter.
如果您有需要检索的数据但在任何情况下都不应该更改:使用getter而不是setter.
如果您有需要为内部目的设置的数据且不应公开公开(并且不能在实例化时设置):使用setter而不是getter(setter可能会阻止第二次调用影响内部属性)
如果你有一些完全是内部的东西,没有其他类需要访问它或直接更改它,那么两者都不使用.
不要忘记,setter和getter可以是私有的,甚至对于内部管理的属性也是如此,拥有管理属性的setter可能是可取的.例如,获取连接字符串并将其传递给HttpURLConnection的setter.
另请注意:
Allen Holub的文章为什么getter和setter方法是邪恶的似乎是OP推理的来源,但在我看来,这篇文章很难解释它的观点.
编辑:添加摘要
编辑2:拼写更正
Fin*_*las 19
看到一个小小的声音少数人反对整个" 吸气者和塞特犬 "的辩护是邪恶的辩论,这是一种耻辱.首先,文章标题是故意挑衅性的吸引你,就像任何博客文章一样.我之前在博客上发表过关于此的博客,几年之后更新了我对这个问题的看法和想法.我会在这里总结一下我能做的最好的事情.
如果你有一堆访问器,你基本上违反了封装.例如:
class Employee
{
public decimal Salary { get; set; }
// Methods with behaviour...
}
Run Code Online (Sandbox Code Playgroud)
这是一个垃圾域对象,因为我可以这样做:
me.Salary = 100000000.00;
Run Code Online (Sandbox Code Playgroud)
这可能只是一个简单的例子,但任何在专业环境中工作的人都可以证明,如果有一些公共人员会使用它.开发人员看到这一点并开始使用Salary在代码库周围添加大量检查以决定如何处理Employee,这不是错误的.
一个更好的对象是:
class Employee
{
private decimal salary;
public void GivePayRise()
{
// Should this employee get a pay rise.
// Apply business logic - get value etc...
// Give raise
}
// More methods with behaviour
}
Run Code Online (Sandbox Code Playgroud)
现在我们不能依赖薪酬作为公共知识.任何想要给员工加薪的人都必须通过这种方法来做到这一点.这很好,因为它的业务逻辑包含在一个地方.我们可以在使用Employee的每个地方更改这个地方并生效.
fic*_*ion 14
以下示例是样板定位器和吸气剂的绝佳示例.
class Item{
private double price;
public void setPrice(final double price){
this.price = price;
}
public double getPrice(){
return this.price;
}
}
Run Code Online (Sandbox Code Playgroud)
一些程序员认为这称为封装,但事实上这段代码完全相同
class Item{
public double price;
}
Run Code Online (Sandbox Code Playgroud)
在这两个类中price都没有受到保护或封装,但第二类更容易阅读.
class Item{
private double price;
public void setPrice(final double price){
if(isValidPrice(price))
this.price = price;
else throw new IllegalArgumentException(price+" is not valid!");
}
public double getPrice(){
return this.price;
}
}
Run Code Online (Sandbox Code Playgroud)
这是一个真正的封装,类的不变量是由守护的setPrice.我的建议 - 不要编写虚拟的getter和setter,只有在他们保护你的类的不变量时才使用getter和setter
我在很多地方都读过"吸气鬼和恶魔都是邪恶的".
真?这听起来很疯狂.许多?告诉我们一个.我们会撕成碎片.
我理解为什么这样.
我不.这对我来说似乎很疯狂.要么你误解了,要么认为你明白了,或者原始来源只是疯了.
但我不知道如何完全避免它们.
你不应该.
怎么避免
getPrice?
看,你为什么要避免这种情况?你怎么想从你的对象中获取数据呢?
怎么避免他们?
别.停止阅读疯狂的谈话.
当有人告诉你 getter 和 setter 是邪恶的时,想想他们为什么这么说。
他们邪恶吗?代码中没有邪恶这样的东西。代码就是代码,没有好坏之分。这只是阅读和调试的难易程度的问题。
在您的情况下,我认为使用 getter 来计算最终价格是完全可以的。
用例:您认为您在购买商品时想要了解商品的价格。
人们有时会像这样使用 getter:
if(item.getPrice() <= my_balance) {
myBank.buyItem(item);
}
Run Code Online (Sandbox Code Playgroud)
这段代码没有任何问题,但它并不像它可能的那样直接。看看这个(更实用的方法):
myBank.buyItem(item); //throws NotEnoughBalanceException
Run Code Online (Sandbox Code Playgroud)
在购买商品时检查商品的价格不是买家或收银员的工作。这实际上是银行的工作。假设客户A有一个SimpleBank.java
public class SimpleBank implements Transaction {
public void buyItem(Item item){
if(getCustomer().getBalance() >= item.getPrice()){
transactionId = doTransaction(item.getPrice());
sendTransactionOK(transactionId);
}
}
}
Run Code Online (Sandbox Code Playgroud)
第一种方法在这里似乎很好。但是如果客户B有一个NewAndImprovedBank.java?
public class NewAndImprovedBank implements Transaction {
public void buyItem(Item item){
int difference = getCustomer().getBalance() - item.getPrice();
if (difference >= 0) {
transactionId = doTransaction(item.getPrice());
sendTransactionOK(transactionId);
} else if (difference <= getCustomer().getCreditLimit()){
transactionId = doTransactionWithCredit(item.getPrice());
sendTransactionOK(transactionId);
}
}
}
Run Code Online (Sandbox Code Playgroud)
在使用第一种方法时,您可能认为您是在防御,但实际上您是在限制系统的功能。
也不要请求许可item.getPrice(),NotEnoughBalanceException而是请求原谅。