Is this a design pattern - returning it from setters?

Is there a name for this:

class A { A* setA() { //set a return this; } A* setB() { //set b return this; } }; 

so you can do something like this:

 A* a = new A; a->setA()->setB(); 

Are there any disadvantages to using this? Benefits?

+7
source share
5 answers

It is known as a chain of methods (a link to frequently asked questions ), and is most often done with links, not pointers.

The method chain is closely related to the Idiom Named Parameter ( Frequently Asked Questions ), as I now, after posting the original version of this answer, see what Steve Jessop discusses in his answer . The NPI idiom is one of the easiest ways to provide a large number of default arguments without causing complexity in constructor calls. For example, this is relevant for programming a graphical interface.

One potential problem with the method chain method is when you want or need to use the NPI idiom for classes in the inheritance hierarchy. Then you will find that C ++ does not support covariant methods . What is it: when you allow your eyes to roam about classes in the chain of class inheritance, then the covariant method is the one whose definition includes some type that, for your wandering eye, changes in its specificity just like the class; s is defined in.

This is the same problem as when defining the clone method, which has the same text definition in all classes, but must be painstakingly repeated in each class to get the correct types.

The solution to this problem is difficult without language support; this is apparently a complex problem, a kind of conflict with a system like C ++. My "How to enter optional arguments in a C ++ 98 blog post" in the appropriate source code to automate the generation of covariant definitions and the article I wrote about this in Dr. Dobbs' journal. Perhaps I will return to that for C ++ 11, or someday, because complexity and possible fragility can appear in the form of more costs than it costs & hellip;

Cheers and hth.,

+9
source

I heard that he used to call something like a chain chain , but I would not call it a design pattern. (Some people also talk about implementing a β€œ free interface ” using this - I have never seen him call it before, but Martin Fowler seems to have written about this a while ago)

You do not lose much by doing this - you can always easily ignore the return result if you do not want to use it like that.

Whatever the cost, I'm less sure. In some cases, this can be rather cryptic. However, this is mainly required for things like operator<< for streaming IO. I would say that this is a call to how it fits into the rest of the code - are people reading it expected / obvious?

(As Steve Jessop noted, this is almost always done with links, but not pointers)

+4
source

Another common use is for parameter objects. Without a chain of methods, they are quite inconvenient to configure, but with them they can be temporary.

Instead:

 complicated_function(P1 param1 = default1, P2 param2 = default2, P3 param3 = default3); 

Record:

 struct ComplicatedParams { P1 mparam1; P2 mparam2; P3 mparam3; ComplicatedParams() : mparam1(default1), mparam2(default2), mparam3(default3) {} ComplicatedParams &param1(P1 p) { mparam1 = p; return *this; } ComplicatedParams &param2(P2 p) { mparam2 = p; return *this; } ComplicatedParams &param3(P3 p) { mparam3 = p; return *this; } }; complicated_function(const ComplicatedParams &params); 

Now I can call it:

 complicated_function(ComplicatedParams().param2(foo).param1(bar)); 

This means that the caller does not need to remember the order of the parameters. Without a chain of methods, which should be:

 ComplicatedParams params; params.param1(foo); params.param2(bar); complicated_function(params); 

I can also call it:

 complicated_function(ComplicatedParams().param3(baz)); 

This means that without defining a ton of overloads, I can specify only the last parameter and leave the rest by default.

The final obvious setup is to make complicated_function member of ComplicatedParams :

 struct ComplicatedAction { P1 mparam1; P2 mparam2; P3 mparam3; ComplicatedAction() : mparam1(default1), mparam2(default2), mparam3(default3) {} ComplicatedAction &param1(P1 p) { mparam1 = p; return *this; } ComplicatedAction &param2(P2 p) { mparam2 = p; return *this; } ComplicatedAction &param3(P3 p) { mparam3 = p; return *this; } run(void); }; ComplicatedAction().param3(baz).run(); 
+3
source

One drawback is that if you deduced a class from A, say like this:

 class Foo : public A { public: Foo *setC() { // set C return this; } }; 

then the order you call setters is important. First you need to call all the settings on Foo: for example, this will not work:

 Foo f=new Foo(); f->setA()->setC(); 

While it will be:

 Foo f=new Foo(); f->setC()->setA(); 
+2
source

It is commonly used, for example, for Boost, but most of the time, functions return links instead:

 A &setX() { // ... return *this; } 
0
source

All Articles