有很多关于 getter 和 setter 是“邪恶”的讨论。
我的问题是:下面的二传手是邪恶的吗?(为简洁起见,其余课程省略)
int balance
public void deposit(int amount)
{
this.balance += amount;
}
此类正在模拟 ATM。在英国,有一些 ATM 可以让您存款和取款,因此该对象需要一种更改其状态(余额)的方法。这个二传手是“邪恶的”吗?
除了没有处理异常情况这一事实之外,它看起来是一个非常好的 OO 方法——它被称为它所做的,它做你所期望的。
我不认为这是人们谈论 getter 和 setter 的意思,因为这不仅仅是将成员设置为给定值。
我不关心 setter 和 getter,但主要是因为我认为我的“对象”是代码库中更高级别的实体。例如(IMO)在课堂外进行操作会“更错误”:
account.SetBalance(account.GetBalance() + depositAmount)
相反,您已经在对象中实现了更高级别的功能;你存了一笔钱,然后让对象找出处理它的正确方法。与我上面给出的 getter/setter 示例相比,这允许对异常条件进行更集中的处理。
这是一个技巧问题吗?我问是因为提供的方法甚至不是“setter”方法。这是一个操作,而不是一个属性。Setter 和 Getter 通常是私有变量(属性)的访问器方法。所以我想你的问题的答案是:
这不是 setter,但作为对对象执行操作的通用方法,它一点也不邪恶。
对于一个类来说,通过 setter 设置值并没有什么坏处,但这更像是一个函数而不是直接的 setter。是的,它设置属性的值,但它通过添加而不是替换先前的值来实现,并且名称不对齐。
真正的“二传手”看起来更像这样:
int balance
private void setBalance(int amount)
{
this.balance = amount;
}
public void deposit(int amount)
{
setBalance(this.balance + amount);
}
但是,对于您的特定 ATM 问题,我非常怀疑 ATM 是否会立即为您的余额添加存款。它可能需要通过单独的机制收集和发布。
就个人而言,我将其称为方法,而不是设置器。刻板的二传手将是
public void deposit(int new_balance)
{
this.balance = new_balance;
}
它所做的只是让您直接访问类的内部,从而破坏通过封装它们和限制访问而获得的任何价值。这就是人们不喜欢它们的原因。
好吧,您可能想检查负数、零数等……但给出要求就可以了。
遵循这个经验法则,你创建的每个变量都应该是最终的,除非它必须更改,并且永远不要为实例变量设置方法,除非你真的希望它们在类之外进行更改。
那不是二传手,它是一种正常的方法
即使是二传手,也不是邪恶的
这是一个邪恶的二传手
int _balance = 0;
public int Balance()
{
get { return _balance; }
set { } //now that's evil!
}
IMO,ATM不应将“余额”作为字段。
(此外,您的“存款”方法不是二传手)
您可能应该有一个带有“余额”字段的 Account 对象,并且可能有一个方便的方法“modifyBalance”,它采用正值来增加余额或负值来减少余额。
然后,当执行这些类型的交易时,您的 ATM 方法将在 Account 对象上调用“modifyBalance”。
您无法判断单个方法是否邪恶,这取决于上下文以及谁可以访问该对象。
如果您对所有字段都有 getter 和 setter,并且每个人和他的狗都可以访问该对象,那么这是非常糟糕的,因为基本上没有数据封装。
另一方面,如果您只为需要它的字段设置了设置器,并且该对象只为少数需要与之通信的其他对象所知,那么这将是完全可以的。
那不是二传手。这是一个普通的方法(或成员函数,或其他)。
setter 是将给定变量设置为给定值的函数,通常是一个坏主意。方法是执行给定类操作的函数。就班级而言,这是有意义的。
如果你有一个奇怪的数据结构,你可能实际上没有一个“平衡”变量。无论你的数据结构是什么,你都必须有一个“存款”功能。有一部分的不同。
不必要; 您提到您想模仿 ATM(自动取款机)的行为。而且您担心自动取款机可以让您存款和取款。但是这些操作,存款和取款,必须是序列化的。你需要你的所有动作都是原子的,所以这种方法比你尝试做更多事情的方法要好。
我看到的一个问题是您在处理金钱时使用的是整数类型。如果这是一个定点数,则不是问题,但没有迹象表明确实如此。