避免空值,不变性,对象状态

时间:2013-02-20 09:44:09

标签: java oop immutability

我喜欢不变性的概念。我也喜欢no nulls的概念(如果可能的话,也没有NullDesignPattern,尽可能没有NullObjects。)

但是下面的场景呢?

我有一个对象User,它有两个字段:birthdaydateInLifeMarried(可以是任何类似的字段;重要的是,这个字段最初是{{1}并且在对象生命中的某些点上发生了变化。)

由于它是不可变的,我希望两个字段都在构造函数中:

null

现在:

  1. 我不想将public User(birthday, dateInLifeMarried) 传递给第二个参数
  2. 我不想添加一个setter,因为它是不可变的
  3. 我不想用NullObjectPattern而不是null
  4. 来调用构造函数

    我只是自相矛盾,还是有 优雅的方式 来拥有它,我不会想到它?

4 个答案:

答案 0 :(得分:13)

你需要考虑你想要的表示 - 而不仅仅是构造函数签名。我怀疑你需要为该字段使用空引用(或至少类似的东西)。但是你可以有两个构造函数:

User(birthday)               // Unmarried user
User(birthday, marriageDate) // Married user; marriageDate must not be null

作为API的用户,我不确定我是否真的喜欢它 - 我想我宁愿允许marriageDate为空。特别是,必须写下来会很烦人:

LocalDate marriageDate = getMarriageDateOrNull();
User user = marriageDate == null ? new User(birthday)
                                 : new User(birthday, marriageDate);

或者,由于人们可以不止一次结婚,你总是可以选择Iterable<LocalDate> marriageDates,然后一个从未结婚的用户会有一个空序列:) (你需要考虑已婚后离婚和已婚丧偶的用户。模拟现实生活很难。)

答案 1 :(得分:1)

第二个构造函数

怎么样?
User(birthday)

调用第一个

this(birthday, null)

答案 2 :(得分:1)

不要为了避免它而避免使用null。考虑null的含义,然后在有意义的地方使用它。值null表示未知未定义未指定值。如果你有意识地使用null,你可以使你的代码更容易使用和更易读,同时防止空指针异常。

在您的示例中,可以不指定结婚日期,因此您应该允许null。但是,您不希望未指定生日,因此您不允许使用null。您可以像这样指定构造函数:

User(LocalDate birthday)
{
    this(birthday, null);
    // That's it! Nothing more to do here.
}

User(LocalDate birthday, LocalDate marriageDate)
{
    if (birthday == null)
        throw new IllegalArgumentException();
    // Use it...
}

现在你(或任何使用你代码的人)可以做这样的事情:

LocalDate marriageDate = getMarriageDateOrNull();
User user = new User(birthday, marriageDate);

请参阅?更清洁的代码,因为您授权 null而不是避免它。

答案 3 :(得分:0)

您可以使用继承:

public abstract class User{}
public class UnMarriedUser extends User{}
public class MarriedUser extends User{}

但是,面对许多排列,这种模式变得越来越弱。