对于一个小型的管理程序,我必须能够登记人员和他们的数据。但是,文件有时是通过电话“动态”创建的,然后将某些数据添加到文件中以完成它。
由于这个原因,我开始用不同的构造函数创建我的Person类,并将它们链接起来,直到我得出结论,我的设计可能很糟糕,因为每个构造函数只添加了一个参数。
经过一些研究,我实现了Builder模式(甚至找到了一个使用好例子类作为示例的Person )。但我不知道这是否适合我的情况。正如我阅读(或理解)的那样,通过Builder模式创建的对象是不可变的。正如我所说的,数据有时会在Person已经创建之后添加(电话号码、电子邮件或地址等)。
这意味着我要改变我的目标,对吗?这样做是不对的。
而且,People有一个地址,但是人们总是可以搬到一个新的位置。因此,我在我的editAddress()类中有一个Address方法。这也意味着我要在创建对象之后更改对象,不是吗?
我计划将这个Person类作为另外两种类型的Person的基类:一个子类和一个父类。那么,我的构建器模式还会有用吗?
我的三个问题是:
使用链式构造函数
public class Person {
private String name;
private String familyName;
private String dateOfBirth;
private Address address;
private String phoneNumber;
private String eMail;
public Person(String name, String familyName) {
this.name = name;
this.familyName = familyName;
}
public Person(String name, String familyName, String dateOfBirth) {
this(name, familyName);
this.dateOfBirth = dateOfBirth;
}
public Person(String name, String familyName, String dateOfBirth, Address address) {
this(name, familyName, dateOfBirth);
this.address = address;
}
public Person(String name, String familyName, String dateOfBirth, Address address, String phoneNumber) {
this(name, familyName, dateOfBirth, address);
this.phoneNumber = phoneNumber;
}
public Person(String name, String familyName, String dateOfBirth, Address address, String phoneNumber, String eMail) {
this(name,familyName,dateOfBirth,address,phoneNumber);
this.eMail = eMail;
}
}使用构建器模式
public class Person {
private final String name;
private final String familyName;
private Date dateOfBirth;
private Address address;
private String phoneNumber;
private String eMail;
public Person(PersonBuilder builder) {
this.name = builder.name;
this.familyName = builder.familyName;
this.dateOfBirth = builder.dateOfBirth;
this.address = builder.address;
this.phoneNumber = builder.phoneNumber;
this.eMail = builder.eMail;
}
@Override
public String toString() {
return String.format("%s %s\n%tD\n%s\nTel:%s\nEmail:%s",this.name,this.familyName,this.dateOfBirth,this.address,this.phoneNumber,this.eMail);
}
public static class PersonBuilder {
private final String name;
private final String familyName;
private Date dateOfBirth = new Date();
private Address address = new Address("Unknown","00","0000","Unknown");
private String phoneNumber = "0000/00 00 00";
private String eMail = "NoEmail@Unknown.be";
public PersonBuilder(String name, String familyName) {
this.name = name;
this.familyName = familyName;
}
public PersonBuilder dateofBirth(Date dateOfBirth) {
this.dateOfBirth = dateOfBirth;
return this;
}
public PersonBuilder address(Address address) {
this.address = address;
return this;
}
public PersonBuilder phoneNumber(String phoneNumber) {
this.phoneNumber = phoneNumber;
return this;
}
public PersonBuilder eMail(String eMail) {
this.eMail = eMail;
return this;
}
public Person build() {
return new Person(this);
}
}
}editAddress方法public void editAddress(Address address){
this.street = address.street;
this.houseNr = address.houseNr;
this.areaCode = address.areaCode;
this.city = address.city;
}发布于 2015-04-12 18:37:41
因此,我开始使用不同的构造函数创建Person类。
只要每个人都能记住构造者所做的事情,那就没问题了。类似C++类参数的默认值。
public Person(String name, // no valid Java
String familyName=null,
String dateOfBirth=null,
Address address=null,
String phoneNumber=null,
String eMail=null)这完全符合你的构造函数和IMHO,它太过火了。闭上你的眼睛,告诉我这封邮件是在电话号码之后还是之前发的。再加第二个电话怎么样?
设计错误,因为每个构造函数只添加了一个参数。
这仅仅是因为Java缺少可选的参数,这很好。问题是太多的参数,其中大多数是字符串。太容易出错了。
但我不知道这是否适合我的情况。
不是因为你不需要它。不变是很棒的,但是即使你放弃了你的设置,仍然有太多愚蠢的工具无法使用不变的Person。
所以这意味着我要改变我的目标,对吗?
对,是这样。您可以通过创建一个包含修改过的数据的新实例来避免这种情况。这很普通,也很好,但你很可能不需要它。实体总是可变的,我会坚持下去。
然后..。我计划为另外两种类型的人(一个子类和一个父类)将这个人类作为我的基类。
考虑避免继承(可能是委托?)。那么孩子成为父母又如何呢?
那么,我的构建器模式还会有用吗?
不..。有授权最好是这样。
使用链式构造函数
让我们称它为“构造函数三角形”。它可能看起来不错,但它不会让你的生活更轻松。我会坚持第一个构造函数。

使用构建器模式
private Date dateOfBirth;Date是史上最差的班级。考虑使用新的Java 8类或Joda-Time。
public Person(PersonBuilder builder) {
...
this.dateOfBirth = builder.dateOfBirth;
this.address = builder.address;
...
}每当您在类中存储可变对象时,这意味着可以在不访问人员的情况下对其进行更改。你应该克隆他们。
private Address address = new Address("Unknown","00","0000","Unknown");"Unknown"、"00"和类似的内容就是您想要呈现给用户的内容。作为一名程序员,您需要一些可以轻松测试的内容,即空字符串。
您的代码大部分都很好,但正如您所看到的,为可变对象构建器没有什么意义。您需要的是流利设置器,这样您就可以编写
Person john = new Person("John", "Doe")
.phoneNumber("123456")
.email("john@doe")
...
.address(address)
.whatever("whatever");这比长度构造函数三角形更容易出错,而且非常容易使用。
您可以将地址扁平化为street、houseNr、areaCode和city,也可以使用对象,但Address应该是不可变的,也可以是setter复制的。或者把它完全压平,完全不创建Address类(不是很好,但很容易)。
我建议您使用项目隆布克,然后您所需要的就是
@Accessors(chain=true, fluent=true) @Getter @Setter
public class Person {
// This is not error-prone and saves you a few chars
public Person(String name, String familyName) {
this.name = name;
this.familyName = familyName;
}
private String name;
private String familyName;
private SomeImmutableDate dateOfBirth;
private String street, houseNr, areaCode, city;
private String phoneNumber;
private String eMail;
}当你需要一个不变的物体时,我建议
@Accessors(chain=true, fluent=true) @Getter @Builder
public class Person {
private final String name;
...
}https://codereview.stackexchange.com/questions/86674
复制相似问题