Null 检查空对象模式

TER*_*ytE 4 c++ null design-patterns object

空对象模式的主要目标是确保向客户端提供可用的对象。所以我们想替换以下代码......

void Class::SetPrivateMemberA() {
    m_A = GetObject();
}

void Class::UseA() {
    if (m_A != null) {
        m_A.Method();
    } else {
        // assert or log the error
    }
}
Run Code Online (Sandbox Code Playgroud)

...通过这个实现:

void Class::SetPrivateMemberA() {
    m_A = GetObject();
}

void Class::UseA() {
    m_A.Method();
}
Run Code Online (Sandbox Code Playgroud)

我想到的问题是 GetObject() 仍然返回一个对象、NULL 对象或其他对象。我喜欢不重复检查 null 并相信发送回的对象可用的想法,但为什么我不在第一个实现中这样做呢?

空对象模式的优点只是稍微增加了清理代码的信任吗?对于第二个实现,在调用 A.Method() 之前检查它是否不为 null 不是一个好习惯吗?

Tan*_*lax 5

你是对的,如果你确定你永远不会返回空值,只需在第一个实现中调用该方法之前跳过空值检查即可。同样,如果您确实需要在UseA()需要对 null 对象执行不同操作的情况下执行一些特殊操作,则无论如何您都需要显式检查 null 对象。然而,空对象模式真正有帮助的是那些并不重要的情况。

以大多数观察者模式为例。如果您将观察者模式实现为只能有一个观察者的类的成员,并且想要向观察者宣布您的类做了某件事,那么观察者是否为 null 对于类来说并不重要。

这也通过空容器类进行了说明,这些类本质上是空对象模式:您只需返回一个空容器,而不是从查询中返回空容器。对于迭代容器的所有条目之类的事情,容器是否为空通常并不重要,因此消除空检查的需要使代码更易于维护/更具可读性。但是,如果您想要填充数据集的视图,您仍然需要显式显示不同的“无条目”。检查空容器。

为清楚起见进行编辑

一个问题是仅从调用站点查看它。与大多数设计模式一样,这需要包含双方才能充分利用。考虑:

public PossiblyNull GetSomethingNull()
{
    if (someBadSituation())
        return null;
    else
        return SomehowProduceSomething();
}
Run Code Online (Sandbox Code Playgroud)

public PossiblyEmpty GetSomethingEmpty()
{
    if (someBadSituation())
        return StaticEmptySomething();
    else
        return ProdueSomethingYay();
}
Run Code Online (Sandbox Code Playgroud)

现在,你的调用代码,而不是看起来像

public void DoSomethingWithChild(Foo foo)
{
    if (foo != null)
    {
        PossiblyNull bar = foo.GetSomething();
        if (bar != null)
            bar.DoSomething();
    }
}
Run Code Online (Sandbox Code Playgroud)

有可能

public void DoSomethingWithChild(Foo foo)
{
    if (foo != null)
        foo.GetSomething().DoSomething();
}
Run Code Online (Sandbox Code Playgroud)