Шаблон C ++ Decorator - PullRequest
       28

Шаблон C ++ Decorator

5 голосов
/ 07 января 2012

У меня есть вектор и несколько классов (расположенных в отдельных файлах) для изменения одного.
Я хочу иметь глобальный доступ к std::vector, но только внутри производных классов когда каждый вызов сохраняет результат предыдущего и последнего объекта должен возвращать общий результат

Не могли бы вы объяснить, как создать высокопроизводительный интерфейс с использованием шаблона Decorator с std::vector?
Я могу ошибаться, и, возможно, понадобится другой шаблон.

// 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)
}

Итак, я не хочу делать так:

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();

/..

И я хочу сделать так:

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

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

У меня есть простая реализация шаблона Decorator.
Но это не совсем то, что мне нужно ((

#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: Извините за неясное объяснение, потому что я не очень хорошо знаю английский

Ответы [ 2 ]

4 голосов
/ 07 января 2012

Из того, что вы описали, Декоратор - это не тот шаблон, на который нужно смотреть.

Мне кажется, что вы просто хотите настроить цепочку трансформаторов для работыобщий вектор - то есть простая функциональная композиция .Это отличается от Декоратор с точки зрения отношения к объекту в ядре - вы не строите что-то, чтобы стоило для вектора, вы строите что-то, чтобы оперировал это.Теперь, когда вы берете несколько преобразователей, вы можете теоретически представить второй и последующие преобразователи как декораторы первого, но, учитывая простоту задействованных объектов, попытка применить реализацию декоратора GoF к вашей ситуации, вероятно, будетбыть излишним.

Вы можете поцеловать, сделав что-то вроде этого:

#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;
}

Есть три простых функции преобразования, каждая из которых написана так, что выходные данные одной из них можно подавать прямо на входследующего.Затем вы можете сделать что-то вроде:

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

ivec v;
xform(v);

, если вы хотите просто статически построить ваше окончательное преобразование и применить его.

В качестве альтернативной реализации, скажем, вы хотели создатькомплект трансформаторов динамически .В этом случае вы можете вставить функции в вектор преобразователей и применить их один за другим:

#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);
}

Этот цикл в конце, кстати, можно еще больше "упростить" с помощью boost::bind и std::for_each если вы так склонны.

Динамическая цепочка трансформаторов имеет некоторое сходство с Chain of Responsibility , за исключением того, что нет концепции, чтобы какой-то конкретный объект остановил цепочку "обрабатывает запрос, т. е. нет реальной ответственности , связанной с этим решением - каждая функция получает равную трещину в векторе.Я бы предположил, что этому шаблону нужно более подходящее имя - оно, вероятно, уже существует, так как такого рода функциональная композиция в ОО-программировании не редкость, но в настоящее время она ускользает от меня.

3 голосов
/ 07 января 2012

Вот так:

#include <vector>
#include <cstdio>

/* A class that operates on an std::vector. */
class Vector
{
public:
    virtual std::vector<int> & getVector() = 0;
    virtual void operation() = 0;
    virtual ~Vector() {}
};

/* Basic implementation of Vector. */
class BasicVector : public Vector {
public:
    BasicVector(std::vector<int> & refVector) : intVector(refVector) {}
    void operation() {
        intVector.push_back(2);
    }
    std::vector<int> & getVector() {
        return intVector;
    }
private:
    std::vector<int> & intVector;
};

/* First decorator. */
class VectorDecorator1 : public Vector
{
public:
    VectorDecorator1(Vector & refVec) : intVec(refVec) {}
    std::vector<int> & getVector() {
        return intVec.getVector();
    }
    void operation() {
        intVec.operation();
        intVec.getVector().push_back(3);
    }
private:
    Vector & intVec;
};

/* Second decorator. Others can be easily added in the future. */
class VectorDecorator2 : public Vector
{
public:
    VectorDecorator2(Vector & refVec) : intVec(refVec) {}
    std::vector<int> & getVector() {
        return intVec.getVector();
    }
    void operation() {
        intVec.operation();
        intVec.getVector().push_back(4);
    }
private:
    Vector & intVec;
};

int main(int argc, char *argv[])
{
    std::vector<int> my_vector;
    my_vector.push_back(1);
    BasicVector basic_vector(my_vector);
    VectorDecorator1 vd1(basic_vector);
    VectorDecorator2 vd2(vd1);
    vd2.operation();
    for(unsigned i = 0; i < my_vector.size(); i++) {
        printf("%d\n", my_vector[i]);
    }
    return 0;
}

Примечание: если вы предпочитаете, легко изменить BasicVector, чтобы он работал на своем собственном std :: vector (вместо ссылки).

...