空对象模式 [英] Null Object Pattern

查看:129
本文介绍了空对象模式的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

似乎有越来越多的人说你永远不应该返回null,而应该总是使用Null对象模式。我可以在使用集合/ map /数组或调用布尔函数(如isAuthenticated(),此处显示

There seems to be a growing community of people saying that you should never return null and should always use the Null Object Pattern instead. I can see the usefullness of the NOP when using a collection/map/array or calling boolean functions such as isAuthenticated(), which is shown here.

我没有发现任何完全令人信服的内容。在我尝试组织我的想法时请耐心等待。

I haven't found anything on this that is fully convincing. Bear with me here as I try to organize my thoughts.

我的理解是,您返回一个已被清零的有效对象,而不是返回一个空对象。 。

My understanding is that instead of returning a null object, you return a valid object that has been "zeroed" out.

例如,客户端会调用一个对象:

So for example, the client would make a call to get an object:

Car car = getCar();

如果不使用NOP,则需要检查从getCar()返回的对象是否为null之前调用它上面的任何方法:

If not using the NOP you would need to check if the object returned from getCar() is null before calling any methods on it:

if (car != null){
    color = car.getColor();
    doScreenStuff(color);
   }

使用NOP,而不是 getCar()返回null,它现在返回一个已被有效清零的Object。所以现在我们不再需要 if(car!= null)并且可以只请求颜色。因此,我认为当我们调用颜色时,我们的归零对象将返回无。

Using the NOP, instead of getCar() returning null, it now returns an Object that has been effectively "zeroed out". So now we no longer need to do if (car != null) and can just request the color. So, I suppose that our "zeroed out" object would return "none" when we call color.

这有什么用?似乎向前移动并在空对象上调用方法会导致像检查null一样痛苦。现在,当需要显示信息时,我们需要检查颜色是否为无,高度不为0,或者您拥有的其他任何值。因此,基本上,如果汽车为空,则不检查处理的开始,而是检查我们拥有的汽车对象是真车还是替代品。 I.E.我们不想显示一堆空对象,所以我们需要一些方法来过滤掉所有空对象。

How does this help? It seems that moving forward and calling methods on an empty object causes just as much pain as just checking null. Now, when it comes time to display the information, we need to check that the color isn't "none", that the height isn't 0, or whatever other values you have. So essentially, instead of checking in the beginning of processing if the car is null, you check afterwards if the car object we have is a real car or a substitute. I.E. we don't want to display a bunch of empty objects, so we need some way to filter out all of our empty objects.

这个过滤是一个额外的步骤,就像调用if(car!= null)一样。唯一的区别是,通过检查null,我们可以在通过抛出异常发现car对象为null时立即停止处理,而使用NOP,我们在空对象上调用方法并继续保持直到它到达时间为止显示对象,此时我们过滤掉空心。此外,您需要知道空对象返回的值。 I.E. getColor()返回无或空。

This filtering is an added step just like calling if (car != null). The only difference is that with checking null, we can stop processing as soon as we discover that the car object is null by throwing an exception, whereas with NOP we call methods on the empty object and keep chugging along until it gets to be time to display the object and at this point we filter out the empties. Furthermore, you need to know the values returned by your empty object. I.E. does getColor() return "none" or "empty".

显然必须有一些我忽略的东西。
提前谢谢。

There obviously must be something I'm overlooking. Thanks in advance.

推荐答案

MattPutnam的答案是正确的,我是第二个。我要补充一点:null对象的概念,当你分析它时,似乎归结为 <的数学概念强>独异 。你可以这样想:monoid是一种具有这两种东西的类型:

MattPutnam's answer is right on point, and I second it. I'd add this: the concept of "null object," when you analyze it, seems to boil down to the mathematical concept of a monoid. You can think of it this way: a monoid is a type that has both of these things:


  1. 追加,总和或类似操作,需要关联 a.op(b).op(c) a.op(b.op(c))。

  2. 空,零或空值,作为中性元素身份元素操作。

  1. An "append," "sum" or similar operation, which needs to be associative: a.op(b).op(c) is the same as a.op(b.op(c)).
  2. An "empty," "zero" or "null" value, that acts as the neutral element or identity element of the operation.

经典的例子null object pattern是返回一个空列表或数组而不是null。好吧,列表是一个monoid,作为操作附加,空列表作为中性元素。

The classic example of the null object pattern is to return an empty list or array instead of null. Well, lists are a monoid, with append as the operation and the empty list as the neutral element.

现在,你在汽车例子是汽车并不是真正的幺半群;没有空车或中性车的概念,并且没有一个明智的操作可以用来将两个 Car 组合成一个。

Now, the problem that you face in your Car example is that Car isn't really a monoid; there is no notion of "the empty car" or "the neutral car", and there isn't really a sensible operation that you could use to combine two Cars into one.

所以你正确得到的建议是使用像Java 8 可选 。诀窍在于,无论 T 是什么类型,可选< T> 是一个幺半群:

So the recommendation you're rightly getting is to use something like the Java 8 Optional. And the trick is that no matter what type T is, Optional<T> is a monoid:


  1. monoid的合并操作是如果不是则选择第一个值,否则选择第二个值:

    • x || empty = x

    • empty || x = x

  1. The monoid's "combine" operation is "pick the first value if it's not empty, otherwise pick the second value":
    • x || empty = x
    • empty || x = x

基本上,可选< T> 是一个添加null的包装器对象没有一个类型的 Car 可选< T> .orElse(T值)方法是选择第一个非值monoid。

So basically, Optional<T> is a wrapper that adds a null object to types like Car that don't have one. The Optional<T>.orElse(T value) method that is a slightly refactored version of the "pick first non-empty value" monoid.

这篇关于空对象模式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆