避免空值,不变性,对象状态
我喜欢不变性的概念。 我也喜欢没有空值的概念(如果可能的话,也尽可能地没有NullDesignPattern,没有NullObjects ...)。
但是,以下情况如何:
我有一个对象User
,它有两个字段: birthday
和dateInLifeMarried
(可以是任何类似的字段;重要的是,起初这个字段为null
并且在对象生命中的某个时刻改变)。
由于它是不可变的,我希望这两个字段都在构造函数中:
public User(birthday, dateInLifeMarried)
现在:
null
传递给第二个参数 null
调用构造函数 我只是与自己相矛盾,还是有一种优雅的方式来拥有它,我没有想到?
那么你需要考虑你想要的表示是什么 - 不仅仅是构造函数签名。 我怀疑你将需要使用空引用(或至少类似的)为该领域。 但是你可以有两个构造函数:
User(birthday) // Unmarried user
User(birthday, marriageDate) // Married user; marriageDate must not be null
作为一个API的用户,我不确定我是否真的喜欢这个 - 但我想我宁愿让marriageDate
为null。 特别是,写下这样的内容会很麻烦:
LocalDate marriageDate = getMarriageDateOrNull();
User user = marriageDate == null ? new User(birthday)
: new User(birthday, marriageDate);
或者,因为人们可以不止一次结婚,所以你总是可以接受一个可以继续使用的Iterable<LocalDate> marriageDates
,然后一个从未结过婚的用户会有一个空序列:)(你需要考虑已婚,离婚和结婚的情况,然后是寡居用户,建模现实生活很困难。)
那么第二个构造函数呢?
User(birthday)
那叫第一个
this(birthday, 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
而不是避免它。