Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ Decorator pattern

I've a vector and several classes (located in separate files) to modify the one.
I want to have global access to the std::vector, but only within the derived classes when each call stores the result of previous and the last object should return the total result

Could you explain how to build a high-performance interface using Decorator pattern with std::vector?
I may be wrong, and may need other pattern.

// A.h
class A () {
      public : 
           vector<int> set(vector<int> &vec);

            //return total result
           vector<int> get() {
               return vector;
           }
};

// B.h
class B () {
    //add new elements into vector
    //for example, add 2,3,4
};

// C.h
class C () {
    //remove some elements from vector
    //for example, remove last element
};

//...

// main.cpp
#include "A.h"
#include "B.h"
#include "C.h"

int main () {

    vector<int> set;
    set.push_back(1); //1

    C obj(new B(new A()));
    obj.set(set);
    obj.get(); // stores 1,2,3 (added by classes A, B, C)
}

So, I don't want to do like this:

vector<int> set1;
set1.push_back(1);

A *A_init;
A_init->set(set1); //add 1

vector<int> set2 = A_init->get();

B *B_init;
B_init->set(set2); //add 2, stores 1,2

vector<int> set3 = B_init->get();

C *C_init;
C_init->set(set3); //add 3, stores 1,2,3

vector<int> set4 = C_init->get();

/..

And I want to do like this:

vector<int> set;
set.push_back(1);

C obj(new B(new A()));
obj.set(set);
obj.get(); // stores 1,2,3

I've a simple impementation of a pattern Decorator.
But it is not quite what I need ((

#include <iostream>
#include <memory>

class A {
    public:
        virtual void operation() = 0;
    };

class Component : public A {
    public:
        virtual void operation() {
            std::cout<<"World!"<<std::endl;
        }
};

class B : public A {
    std::unique_ptr<A> add;

public:
    B(A *component): add(component) {}

    virtual void operation() {
        std::cout << ", ";
        add->operation();
    }
};

class C : public A {
    std::unique_ptr<A> add;

public:
    C(A *component): add(component) {}

    virtual void operation() {
            std::cout << "Hello";
            add->operation();
    }
};

int main() {
    C obj(new B(new Component()));
    obj.operation(); // prints "Hello, World!\n"

    return 0;
}

PS: Sorry for not so clear explanation, because I don't know English so well

like image 663
Duglas Avatar asked Jan 06 '12 20:01

Duglas


People also ask

What is Decorator design pattern C++?

Decorator in C++ Decorator is a structural pattern that allows adding new behaviors to objects dynamically by placing them inside special wrapper objects, called decorators. Using decorators you can wrap objects countless number of times since both target objects and decorators follow the same interface.

What does decorator pattern do?

In object-oriented programming, the decorator pattern is a design pattern that allows behavior to be added to an individual object, dynamically, without affecting the behavior of other objects from the same class.

Does C have design patterns?

Yes, there are. Lazy initialization, singleton, object pool, object state etc.

What is decoration in C?

Functions, data, and objects in C and C++ programs are represented internally by their decorated names. A decorated name is an encoded string created by the compiler during compilation of an object, data, or function definition.


1 Answers

From what you've described, Decorator is not the pattern to be looking at.

It sounds to me like you simply want to set up a chain of transformers to operate upon a common vector – i.e. a simple functional composition. This differs from Decorator in terms of the relationship to the object at the core - you are not building something to stand in for a vector, you are building something to operate upon it. Now when you take multiple transformers, you could theoretically imagine the second and later transformers as decorators of the first, but given the simplicity of the objects involved, trying to apply the GoF decorator implementation to your situation is probably going to be overkill.

You can KISS by doing something like this:

#include <vector>

using namespace std;
typedef vector<int> ivec;

ivec& a(ivec& v) {
    v.push_back(1);
    return v;
}

ivec& b(ivec& v) {
    v.push_back(2);
    v.push_back(3);
    v.push_back(4);
    return v;
}

ivec& c(ivec& v) {
     v.pop_back();
     return v;
}

There are three simple transformation functions, each written so that the output of one can be fed right into the input of the next. Then you can do something like:

ivec& xform(ivec& v) {
    return c(b(a(v)));
}

ivec v;
xform(v);

if you want to just build up your final transform statically and apply it.

As an alternate implementation, let's say you wanted to build up a set of transformers dynamically. In that case, you can push the functions into a vector of transformers and apply them one by one:

#include <vector>
using namespace std;

typedef ivec& (*ivec_xformer)(ivec&);
typedef vector<ivec_xformer> xform_vec;
xform_vec xforms;
xforms.add(&a);
xforms.add(&b);
xforms.add(&c);

ivec v;
for (xform_vec::iterator i = xforms.begin(); i != xforms.end(); ++i) {
   (*i)(v);
}

This loop at the end, btw, can be further "simplified" with boost::bind and std::for_each if you're so inclined.

The dynamic chain of transformers bears some resemblance to a Chain of Responsibility, except that there's no concept of having a particular object stop the chain by "handling" the request, i.e. there's no real responsibility associated with this solution – each function gets an equal crack at the vector. I'd suggest this pattern needs a better name – one probably already exists out there, as this kind of functional composition in OO programming is not uncommon, but it eludes me at the moment.

like image 187
Owen S. Avatar answered Sep 28 '22 10:09

Owen S.