首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >人事登记制度

人事登记制度
EN

Code Review用户
提问于 2015-04-12 17:04:56
回答 1查看 866关注 0票数 6

对于一个小型的管理程序,我必须能够登记人员和他们的数据。但是,文件有时是通过电话“动态”创建的,然后将某些数据添加到文件中以完成它。

由于这个原因,我开始用不同的构造函数创建我的Person类,并将它们链接起来,直到我得出结论,我的设计可能很糟糕,因为每个构造函数只添加了一个参数。

经过一些研究,我实现了Builder模式(甚至找到了一个使用好例子类作为示例的Person )。但我不知道这是否适合我的情况。正如我阅读(或理解)的那样,通过Builder模式创建的对象是不可变的。正如我所说的,数据有时会在Person已经创建之后添加(电话号码、电子邮件或地址等)。

这意味着我要改变我的目标,对吗?这样做是不对的。

而且,People有一个地址,但是人们总是可以搬到一个新的位置。因此,我在我的editAddress()类中有一个Address方法。这也意味着我要在创建对象之后更改对象,不是吗?

我计划将这个Person类作为另外两种类型的Person的基类:一个子类和一个父类。那么,我的构建器模式还会有用吗?

我的三个问题是:

  1. 在创建对象之后添加数据可以吗?(如果没有,我应该如何处理这个问题?)
  2. 可以在底层类中使用更改数据的方法吗?(如果没有,我应该如何处理这个问题?)
  3. 一旦我从子类(子类和父类)开始,这是否仍然是有用的?

使用链式构造函数

我的第一段代码

代码语言:javascript
复制
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;
    }

}

使用构建器模式

我的代码

代码语言:javascript
复制
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方法

代码语言:javascript
复制
public void editAddress(Address address){
        this.street = address.street;
        this.houseNr = address.houseNr;
        this.areaCode = address.areaCode;
        this.city = address.city;
    }
EN

回答 1

Code Review用户

回答已采纳

发布于 2015-04-12 18:37:41

因此,我开始使用不同的构造函数创建Person类。

只要每个人都能记住构造者所做的事情,那就没问题了。类似C++类参数的默认值。

代码语言:javascript
复制
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

所以这意味着我要改变我的目标,对吗?

对,是这样。您可以通过创建一个包含修改过的数据的新实例来避免这种情况。这很普通,也很好,但你很可能不需要它。实体总是可变的,我会坚持下去。

然后..。我计划为另外两种类型的人(一个子类和一个父类)将这个人类作为我的基类。

考虑避免继承(可能是委托?)。那么孩子成为父母又如何呢?

那么,我的构建器模式还会有用吗?

不..。有授权最好是这样。

最终转到代码

使用链式构造函数

我的第一段代码

让我们称它为“构造函数三角形”。它可能看起来不错,但它不会让你的生活更轻松。我会坚持第一个构造函数。

使用构建器模式

我的代码

代码语言:javascript
复制
private Date dateOfBirth;

Date是史上最差的班级。考虑使用新的Java 8类或Joda-Time。

代码语言:javascript
复制
public Person(PersonBuilder builder) {
    ...
    this.dateOfBirth = builder.dateOfBirth;
    this.address = builder.address;
    ...
}

每当您在类中存储可变对象时,这意味着可以在不访问人员的情况下对其进行更改。你应该克隆他们。

代码语言:javascript
复制
private Address address = new Address("Unknown","00","0000","Unknown");

"Unknown""00"和类似的内容就是您想要呈现给用户的内容。作为一名程序员,您需要一些可以轻松测试的内容,即空字符串。

摘要

您的代码大部分都很好,但正如您所看到的,为可变对象构建器没有什么意义。您需要的是流利设置器,这样您就可以编写

代码语言:javascript
复制
Person john = new Person("John", "Doe")
    .phoneNumber("123456")
    .email("john@doe")
    ...
    .address(address)
    .whatever("whatever");

这比长度构造函数三角形更容易出错,而且非常容易使用。

您可以将地址扁平化为street、houseNr、areaCode和city,也可以使用对象,但Address应该是不可变的,也可以是setter复制的。或者把它完全压平,完全不创建Address类(不是很好,但很容易)。

我建议您使用项目隆布克,然后您所需要的就是

代码语言:javascript
复制
@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;
}

不变版本

当你需要一个不变的物体时,我建议

代码语言:javascript
复制
@Accessors(chain=true, fluent=true) @Getter @Builder
public class Person {
    private final String name;
    ...
}
票数 6
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/86674

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档