C++中的长代理链

Ser*_* K. 22 c++ design-patterns delegation method-chaining chaining

这绝对是主观的,但我想尽量避免它变得有争议.我认为如果人们适当地对待它可能是一个有趣的问题.

在我最近的几个项目中,我曾经实现过长代理链是常见的架构.

可能经常遇到双重委托链:

bool Exists = Env->FileSystem->FileExists( "foo.txt" );
Run Code Online (Sandbox Code Playgroud)

三重代表团并不罕见:

Env->Renderer->GetCanvas()->TextStr( ... );
Run Code Online (Sandbox Code Playgroud)

存在更高级别的代表团,但实际上很少.

在上述示例中,不执行NULL运行时检查,因为所使用的对象始终存在并且对于程序的运行是至关重要的并且在执行开始时被显式构造.基本上我曾经在这些情况下拆分委托链:

1)我重用通过委托链获得的对象:

{ // make C invisible to the parent scope
   clCanvas* C = Env->Renderer->GetCanvas();
   C->TextStr( ... );
   C->TextStr( ... );
   C->TextStr( ... );
}
Run Code Online (Sandbox Code Playgroud)

2)在使用之前,应该检查委托链中间某处的中间对象是否为NULL.例如.

clCanvas* C = Env->Renderer->GetCanvas();

if ( C ) C->TextStr( ... );
Run Code Online (Sandbox Code Playgroud)

我曾经通过提供代理对象来对抗案例(2),以便可以在非NULL对象上调用方法,从而产生empty结果.

我的问题是:

  1. 案例(1)或(2)是模式还是反模式?
  2. 有没有更好的方法来处理C++中的长委托链?

以下是我在做出选择时考虑的一些优缺点:

优点:

  • 它非常具有描述性:从一行代码中可以清楚地看出对象来自哪里
  • 长代表团看起来不错

缺点:

  • 交互式调试很费力,因为很难检查委托链中的多个临时对象

我想知道长代表团的其他利弊.请根据有争议的观点提出你的推理和投票,而不是你对它的看法.

bit*_*ask 14

我不会到目前为止称为反模式.但是,第一个缺点C是即使在逻辑相关(太过无端的范围)之后,您的变量也是可见的.

您可以使用以下语法解决此问题:

if (clCanvas* C = Env->Renderer->GetCanvas()) {
  C->TextStr( ... );
  /* some more things with C */
}
Run Code Online (Sandbox Code Playgroud)

这在C++中是允许的(虽然它不在C中)并且允许您保持适当的范围(C作用域,就好像它在条件的块内)并检查NULL.

断言某事不是NULL绝不会比被SegFault杀死更好.所以我不建议简单地跳过这些检查,除非你100%确定该指针永远不会是NULL.


此外,如果您觉得特别花哨,您可以将支票封装在一个额外的免费功能中:

template <typename T>
T notNULL(T value) {
  assert(value);
  return value;
}

// e.g.
notNULL(notNULL(Env)->Renderer->GetCanvas())->TextStr();
Run Code Online (Sandbox Code Playgroud)


wil*_*ilx 6

根据我的经验,像这样的链条通常包含不那么微不足道的吸气剂,导致效率低下.我认为(1)是一种合理的方法.使用代理对象似乎有点矫枉过正.我宁愿看到NULL指针崩溃而不是使用代理对象.

  • 它可能是任务关键代码中间某处的潜在崩溃. (2认同)

APr*_*mer 6

如果遵循得墨忒耳法则,这种长期的授权链不应该发生.我经常和它的一些支持者争论说,他们认真地对待它,但是如果你想到如何最好地处理长授权链,那么你应该更多地遵守它的建议.