背景:
我找到了 this article在 JavaWorld 上,Allen Holub 解释了 Getters/Setters 的替代方法,该方法维护对象的实现应该被隐藏的原则(他的示例代码也可以在下面找到)。
据解释,类 Name
/EmployeeId
/Money
应该有一个采用单个字符串的构造函数 - 原因是如果你将其键入为 int
,稍后需要将其更改为 long
,您将不得不修改该类的所有用途,而使用此模式您无需必须。
问题一:
我在想:这不是简单地将问题转移到解析被抛来抛去的 String
参数上吗?例如,如果所有使用 EmployeeId
的代码(从 Exporter
接收)将 String
解析为 int
, 突然你开始导出 long
值,你需要修改完全一样多的用途......如果你开始将它解析为 long
它可能必须改变到一个 double
(即使这对 id 没有意义)...如果您不能确定将 String
解析成什么,您可以'执行任何操作。
问题2:
除了这个问题,我还有另一个问题:我知道这篇文章已有七年多了,所以有人能给我指出一些最近关于 OO 设计的概述,特别是关于 getter/setter 和实现隐藏辩论的想法吗?
list 1. Employee:Builder 上下文
public class Employee
{ private Name name;
private EmployeeId id;
private Money salary;
public interface Exporter
{ void addName ( String name );
void addID ( String id );
void addSalary ( String salary );
}
public interface Importer
{ String provideName();
String provideID();
String provideSalary();
void open();
void close();
}
public Employee( Importer builder )
{ builder.open();
this.name = new Name ( builder.provideName() );
this.id = new EmployeeId( builder.provideID() );
this.salary = new Money ( builder.provideSalary(),
new Locale("en", "US") );
builder.close();
}
public void export( Exporter builder )
{ builder.addName ( name.toString() );
builder.addID ( id.toString() );
builder.addSalary( salary.toString() );
}
//...
}
最佳答案
问题 1:
字符串解析似乎很奇怪。恕我直言,您只能做这么多来预测 future 的增强功能。您要么从一开始就使用 long
参数来确定,要么考虑稍后添加其他构造函数。或者,您可以引入一个可扩展的参数类。见下文。
问题 2: 构建器模式可用于多种场景。
复杂对象创建
当您处理具有许多属性的非常复杂的对象时 你最好只在对象创建时设置一次,用 常规构造函数会变得难以阅读,因为构造函数将 有一长串参数。将其发布为 API 不是好的风格 因为每个人都必须仔细阅读文档并确保 他们不会混淆参数。
相反,当您提供构建器时,您只需要处理(私有(private)的) 构造函数接受所有参数,但是你的类的消费者可以 使用更具可读性的单独方法。
Setter 不是一回事,因为它们允许您更改对象 创建后的属性。
可扩展的 API
当你只为你的类发布一个多参数构造函数时 决定你需要添加一个新的(可选的)属性(比如在你的软件的更高版本中) 您必须创建与第一个构造函数相同的第二个构造函数,但是 再接受一个参数。否则 - 如果您只是将它添加到现有的 构造函数 - 你会破坏与现有代码的兼容性。
使用构建器,您只需为新属性添加一个新方法,所有现有 代码仍然兼容。
不变性
软件开发强烈倾向于并行执行 多个线程。在这种情况下,最好使用不能 在创建它们(不可变对象(immutable对象))之后进行修改,因为这些 不会导致来自多个线程的并发更新出现问题。这是 为什么 setter 不是一个选项。
现在,如果你想避免多参数公共(public)构造函数的问题, 这使得构建器成为一个非常方便的替代方案。
可读性(“Fluent API”)
如果构建器的方法是 巧妙地命名,你可以写出读起来几乎像英语句子的代码。
一般来说,构建器是一种有用的模式,并且根据您使用的语言,对于 API 的提供者来说,它们要么非常易于使用(例如 Groovy),要么有点乏味(例如在 Java 中)。然而,对于消费者而言,它们可能同样简单。
关于面向对象的 JavaWorld : Getters/Setters vs Builder,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6927292/