2

在java中,我们更喜欢null object模式而不是在所有引用中使用非空检查来混乱代码。最近我们遇到了一个null object通过保留singleton对象来使用的问题。
假设我们有Person如下类

public class Person {
 public String firstName;
 public String lastName;
 public boolean isNull() {
  return false;
 }
 public static final Person NULL = new Person() {
  public boolean isNull() { return true; }  
 }
}

在这种情况下,尽管我已将NULLobject 声明为 final,但我仍然可以修改成员变量及其全局可用。

Person nullRef = Person.NULL;
Person.NULL.firstName = "sample";
System.out.println(nullRef.firstName);

在这种情况下,它只有三个字段,我可以通过覆盖这三个 getter 方法来解决可变性问题。但实际上会有很多字段很难覆盖所有相应的 getter 方法。
是否有任何标准模式或策略来解决NULL对象中的这种可变性问题?

4

3 回答 3

2

使用 Google Guava 库中的 Optional

Optional<Integer> possible = Optional.of(5);
possible.isPresent(); // returns true
possible.get(); // returns 5

引用库文档:

除了通过给 null 命名来增加可读性之外,Optional 的最大优点是它的 idiot-proof-ness

这是处理空对象的更自然的方式

可选的谷歌番石榴

于 2012-12-03T12:33:35.667 回答
1

您需要有两个级别的接口:一个用于不可变部分(仅 getter 和不可变方法),另一个用于扩展不可变接口的可变部分。然后需要重构代码以仅在所有相关位置使用最严格的接口。

所以

public interface ImmutablePerson {
  final String getFirstName();
}

public interface MutablePerson extends ImmutablePerson {
  final void setLastName(final String newName);
}

是的,现在 MutablePerson “是” ImmutablePerson,但仅在用作一个时:)

此外,isNull 检查表明您需要更多地考虑控制反转。

具体来说:

当你发现自己在写代码时

if (!person.isNull()) {
  person.setLastName("Foo");
}

相反,您应该只使用 Null 对象并将其视为已插入的中性元素。像这样:

第一的:

final Person NullPerson = new Person() {
  void setLastName(final String newName) {
    // Do nothing, this is a neutral (Null) object
  }
}

...然后稍后:

// Never need to check for isNull ever again - null objects just decide to ignore your request
person.setLastName("Foo");
于 2012-12-03T10:50:03.050 回答
0
  • 您需要将所有字段设为“私有”,以便除 getter 代码外无法访问这些字段。
  • 您需要修改“setter”方法而不是 getter 方法以使其不可变。例如。

    public String setFirstName(String name){ if(!isNull()){ firstName = name; } }

于 2012-12-03T10:45:05.350 回答