这是一个设计模式吗?从setters返回
Is this a design pattern - returning this from setters?
这个有名字吗:
class A
{
A* setA()
{
//set a
return this;
}
A* setB()
{
//set b
return this;
}
};
所以你可以做这样的事情:
A* a = new A;
a->setA()->setB();
使用这个有什么缺点吗?优点?
它被称为方法链接(FAQ链接(,通常使用引用而不是指针。
方法链接与命名参数习语(常见问题解答链接(密切相关,正如我现在所说,在发布了这个答案的初始版本后,请参阅Steve Jessop在他的答案中所讨论的内容。NPI习惯用法是一种简单的方法,可以提供大量默认参数,而不会将复杂性强加给构造函数调用。例如,这与GUI编程相关。
方法链接技术的一个潜在问题是,当您希望或需要将NPI习惯用法应用于继承层次结构中的类时。然后您发现C++不支持协变方法。这就是:当你让你的眼睛在类继承链中的类上下徘徊时,协变方法的定义涉及某种类型,对你来说,这种类型的特异性与它在类中定义的方式相同。
这与定义clone
方法的问题大致相同,该方法在所有类中都有相同的文本定义,但必须在每个类中费力地重复才能获得正确的类型。
没有语言支持很难解决这个问题;这似乎是一个本质上复杂的问题,与C++类型的系统有一种冲突。我的"如何在C++98中进行键入的可选参数"博客文章链接到用于自动生成协变定义的相关源代码,以及我在多布斯博士期刊上写的一篇关于它的文章。也许我会在C++11中重新审视这一点,或者某个时候,因为复杂性和可能的脆性可能看起来比它的价值更大…
我以前听说过它被称为"方法链接",但我不会称它为设计模式。(有些人还谈到使用这个实现"流畅的界面"——不过我以前从未见过它这么叫,但Martin Fowler似乎早就写过了(
这样做不会损失太多——如果你不想那样使用它,你可以很高兴地忽略返回结果。
至于它值得做吗,我不太确定。在某些情况下,它可能相当神秘。然而,对于operator<<
之类的基于流的IO,基本上需要。我想说,这是一个关于它如何与代码的其余部分相适应的呼吁——它对阅读它的人来说是预期的/显而易见的吗?
(正如Steve Jessop所指出的,这几乎总是通过引用而不是指针来完成的(
另一个常见的ish用法是"参数对象"。如果没有方法链接,它们的设置非常不方便,但有了它,它们可以是临时的。
代替:
complicated_function(P1 param1 = default1, P2 param2 = default2, P3 param3 = default3);
写入:
struct ComplicatedParams {
P1 mparam1;
P2 mparam2;
P3 mparam3;
ComplicatedParams() : mparam1(default1), mparam2(default2), mparam3(default3) {}
ComplicatedParams ¶m1(P1 p) { mparam1 = p; return *this; }
ComplicatedParams ¶m2(P2 p) { mparam2 = p; return *this; }
ComplicatedParams ¶m3(P3 p) { mparam3 = p; return *this; }
};
complicated_function(const ComplicatedParams ¶ms);
现在我可以称之为:
complicated_function(ComplicatedParams().param2(foo).param1(bar));
这意味着调用者不必记住参数的顺序。如果没有方法链接,则必须是:
ComplicatedParams params;
params.param1(foo);
params.param2(bar);
complicated_function(params);
我也可以称之为:
complicated_function(ComplicatedParams().param3(baz));
这意味着,在不必定义大量重载的情况下,我可以只指定最后一个参数,并将其余参数保留为默认值。
最后一个明显的调整是使complicated_function
成为ComplicatedParams
:的成员
struct ComplicatedAction {
P1 mparam1;
P2 mparam2;
P3 mparam3;
ComplicatedAction() : mparam1(default1), mparam2(default2), mparam3(default3) {}
ComplicatedAction ¶m1(P1 p) { mparam1 = p; return *this; }
ComplicatedAction ¶m2(P2 p) { mparam2 = p; return *this; }
ComplicatedAction ¶m3(P3 p) { mparam3 = p; return *this; }
run(void);
};
ComplicatedAction().param3(baz).run();
一个缺点是,如果你从a派生一个类,比如说:
class Foo : public A
{
public:
Foo *setC()
{
// set C
return this;
}
};
那么你称之为二传手的顺序很重要。你需要先调用Foo上的所有setter:例如,这不起作用:
Foo f=new Foo();
f->setA()->setC();
而这将:
Foo f=new Foo();
f->setC()->setA();
它通常用于Boost,但大多数时候函数会返回引用:
A &setX()
{
// ...
return *this;
}
- 来自 std::list 的迭代器 .end() 按预期返回"0xcdcdcdcdcdcdcdcd"但 .begin()
- 什么时候在C++中返回常量引用是个好主意
- 你能重载对象变量名本身返回的内容吗
- 为什么 Serial.println(<char[]>);返回随机字符?
- C++映射:具有自定义类的运算符[]不起作用(总是返回0)
- 如何获取std::result_of函数的返回类型
- QueryWorkingSet总是返回false
- (C++)分析树以计算返回错误值的简单算术表达式
- 访问者访问变体并返回不同类型时出错
- 如何返回一个类的两个对象相加的结果
- OpenInventor从9.8升级到10.4.2后,GLSL纹理返回零
- lower_bound()返回最后一个元素
- "throw expression code" 1e7 >返回 d 是什么?投掷标准::overflow_error( "too big" ) : d;意味 着?
- 奇怪的(对我来说)返回声明 - 在谷歌上找不到任何关于它的信息
- 如何取消对nullptr的屏蔽,返回正确的对象
- 奇怪的结构&GCC&clang(void*返回类型)
- 架构决策:返回std::future还是提供回调
- 从python中调用C++函数并获取返回值
- 矩阵向量乘法(cublasDgemv)返回零
- 这是一个设计模式吗?从setters返回