这是否有名称:
class A
{
A* setA()
{
//set a
return this;
}
A* setB()
{
//set b
return this;
}
};
所以你可以这样做:
A* a = new A;
a->setA()->setB();
使用它有什么缺点吗?优点
答案 0 :(得分:9)
它被称为方法链接(FAQ link),更常见的是引用,而不是指针。
方法链接与命名参数习惯(FAQ link)密切相关,正如我现在发布此答案的初始版本后,请参阅Steve Jessop discusses in his answer。 NPI习惯用法是提供大量默认参数的一种简单方法,而不会强制构造函数调用的复杂性。例如,这与GUI编程有关。
方法链接技术的一个潜在问题是,您希望或需要在继承层次结构中为类应用NPI习惯用法。然后你发现C ++不支持协变方法。那是什么:当你让你的眼睛在类继承链中向上或向下徘徊时,那么一个协变方法是一个定义涉及某种类型的方法,对于你的流浪眼睛来说,它的特异性与它定义的类相同。英寸
与定义clone
方法的问题大致相同,{{1}}方法在所有类中都有相同的文本定义,但必须在每个类中费力地重复才能使类型正确。
没有语言支持,解决这个问题很难;它似乎是一个固有的复杂问题,与C ++类型系统发生冲突。我的“How to do typed optional arguments in C++98” blog post链接到相关的源代码,用于自动生成协变定义,以及我在Dobbs Journal博士上写的一篇文章。也许我会重新考虑一下C ++ 11,或者某个时候,因为复杂性和可能的脆弱性可能会显得比它的价值更高......
干杯&第h。,
答案 1 :(得分:4)
我之前听说它叫“method chaining”,但我不会称之为设计模式。 (有些人还谈到使用这个实现“fluent interface” - 我之前从未见过它,但是Martin Fowler似乎已经写了一段时间了)
通过这样做你不会失去太多 - 如果你不想那样使用它,你总是可以非常愉快地忽略返回结果。
至于值得做的事我不太确定。在某些情况下,它可能非常神秘。但是,对于基于流的IO,operator<<
这样的事情基本上是 required 。我想说这是关于它如何与其余代码相匹配的一个电话 - 对于阅读它的人来说是期望/显而易见的吗?
(正如Steve Jessop指出的那样,几乎总是用引用完成,而不是指针)
答案 2 :(得分:3)
另一个常见的用法是使用“参数对象”。没有方法链接,它们设置起来非常不方便,但有了它,它们可能是临时的。
而不是:
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();
答案 3 :(得分:2)
一个缺点是,如果你从A派生一个类,比如说:
class Foo : public A
{
public:
Foo *setC()
{
// set C
return this;
}
};
然后你调用setter的顺序很重要。你需要首先调用Foo上的所有setter:例如,这不起作用:
Foo f=new Foo();
f->setA()->setC();
这将:
Foo f=new Foo();
f->setC()->setA();
答案 4 :(得分:0)
它通常用于例如Boost,但大多数情况下函数返回引用:
A &setX()
{
// ...
return *this;
}