修改 setter 参数是否正常?假设我们有 setString 方法。我们真的想保留字符串的修剪形式。所以带有尾随空格的字符串是无效的,但我们不想抛出异常。
最好的解决方案是什么?修剪设置器中的值,例如
public void setString(String string) {
this.string = string.trim();
}
或者在调用者中修剪它(不止一次),例如
object.setString(string.trim());
或者也许是别的什么?
修改 setter 参数是否正常?假设我们有 setString 方法。我们真的想保留字符串的修剪形式。所以带有尾随空格的字符串是无效的,但我们不想抛出异常。
最好的解决方案是什么?修剪设置器中的值,例如
public void setString(String string) {
this.string = string.trim();
}
或者在调用者中修剪它(不止一次),例如
object.setString(string.trim());
或者也许是别的什么?
是的。毕竟,setter 是为这类事情而设计的!控制和清理写入字段的值;)
完全。这是一个示例:假设您有一个具有不同类型测量单位的工程程序。您将内部值保留在一个测量系统中,但您从 setter 中的所有其他值转换,然后在 getter 中转换回来,例如:
public double UserTemperature
{
get
{
return Units.Instance.ConvertFromSystem(UnitType.Temperature, temperature);
}
set
{
double v = Units.Instance.ConvertToSystem(UnitType.Temperature, value);
if (temperature != v)
{
temperature = v;
Changed("SystemTemperature");
Changed("UserTemperature");
}
}
}
是的,当然。在应用任何方法(例如 trim())之前,请小心检查 NULL。
有两所学校:一个说可以在 setter 中检查参数(学校风格),第二个说 bean 不应该包含任何逻辑,只包含数据(企业风格)。
我更相信第二个。您多久查看一次 bean 的实现?getUser 应该抛出任何异常还是只返回null?
当您将逻辑放入您的 setter 和 getter 中时,您会更难理解发生了什么,因为许多人永远不会查看它的实现。如果您不同意,我敦促您在使用它之前查看每个 setter 和 getter 实现,以检查它是否不仅仅是一个 bean。
乍一看,它似乎违反了最小惊讶原则。如果我是您班级的用户,我希望二传手能完全按照我的吩咐去做。我会在设置器中抛出异常以强制用户修剪输入。
另一种(更好的?)替代方法是将方法的名称更改为 trimAndSetString。这样,修剪输入的行为就不足为奇了。
如果我错了,请纠正我,但在我看来,setter 应该持有这种逻辑是合乎逻辑的。如果 setter 只是为内部 var 分配了一些值而不检查它,那么为什么不公开 var 本身呢?
这正是您使用 setter 而不是将对象字段公开给整个世界的原因。
考虑一个持有整数角度的类,该角度预计在 0 到 359 之间(包括 0 到 359)。
如果您公开该字段,调用函数可以将其设置为他们想要的任何内容,这将破坏您的 API 指定的合同。它也可能会在某个地方破坏您的功能,因为您的代码被编写为假定该变量的某个范围。
使用二传手,您可以做很多事情。一种是引发异常以指示传递了无效值,但在我看来这是不正确的(对于这种情况)。如果将输入值修改为 0 到 359 之间的值,例如:
actualVal = passedValue % 360;
只要在您的界面 (API) 中指定了这一点,它就完全有效。事实上,即使你没有指定它,你仍然可以自由地做任何你想做的事情,因为调用者违反了合同(通过传递一个超出范围的值)。我倾向于遵循“尽快清理您的输入”的规则。
在您的特定情况下,只要您指定字符串以修剪格式存储,调用者就没有理由抱怨(您已经声明这样的字符串无效)。就代码大小(而不是速度)而言,最好在 setter 中而不是在每段调用 setter 的代码中执行。它还保证字符串按您期望的方式存储 - 不能保证调用者不会意外(或故意)存储未修剪的字符串。
是的。面向对象设计的一个特点是调用者可以把你的类当作一个黑盒子。你在里面做的事是你自己的事,只要接口的行为有文档且合乎逻辑。
虽然不同的人有不同的理念,但我建议属性设置器仅适用于他们将设置对象状态的一个方面以匹配指示值并可能通知任何关心更改但不会影响对象的状态(如果该属性是根据与属性设置器关联的状态定义的,则属性设置器更改只读属性的值是完全正确的;例如,控件的只读Right属性可以在其条款Bounds)。如果属性设置器无法执行指定的操作,则应抛出异常。
如果希望允许客户端以某种不符合上述描述的方式修改对象的状态,则应该使用方法而不是属性。如果有人调用Foo.SetAngle(500),则可以合理地预期该方法将使用指定的参数来设置角度,但该Angle属性可能不会以与设置相同的形式返回角度(例如,它可能返回 140)。另一方面,如果Angle是一个读写属性,人们会期望写入 500 的值将被禁止,否则会导致该值读回 500。如果想要让对象存储范围内的角度从 0 到 359,该对象还可以有一个称为只读属性的属性BaseAngle,该属性将始终以该形式返回一个角度。