Недавно я услышал об абстрактном фабричном шаблоне, и в настоящее время у меня есть некоторые сомнения относительно того, как разработать такой шаблон, когда нужны параметризованные конструкторы.
Точнее, насколько я понял, одно из основных преимуществ этого шаблона проектирования. заключается в облегчении управления кодом, поскольку всякий раз, когда в систему вводится новый тип, необходимо адаптировать одну фабричную функцию, в которой вызываются конструкторы объектов.
Большинство примеров, которые я нашел, рассматривают только пустые конструкторы. (скажем, конструкторы по умолчанию).
Но что произойдет, если нужно использовать параметризованные конструкторы? Работает ли этот шаблон проектирования по-прежнему?
Поскольку параметры могут различаться по типу и количеству в производных классах, нужно ли учитывать несколько фабричных функций? Ниже я привожу пример того, чего я хотел бы достичь. Обратите внимание, что для сокращения количества строк кода я рассмотрел только один конструктор для каждого класса, который служит как конструктором по умолчанию, так и параметризованным конструктором.
class Shape {
public:
Shape(){std::cout << "Calling Shape Constructor\n";};
virtual ~Shape(){std::cout << "Calling Shape Desstructor\n";};
virtual void draw() const = 0;
virtual void doSomething1(int) const = 0;
virtual void doSomething2(int, float) const = 0;
};
class Rectangle : public Shape {
public:
Rectangle(int l = 0, int b = 0 ):l(l),b(b){ std::cout << "Calling Rectangle Constructor\n"; };
~Rectangle(){ std::cout << "Calling Rectangle Destructor\n\n"; };
virtual void draw() const{ /* Draw Rectangle */ };
virtual void doSomething1(int) const { /* doSomething1 */};
virtual void doSomething2(int, float) const { /* doSomething2 */};
private:
int l,b;
};
class Circle : public Shape {
public:
Circle(int r = 0):r(r){ std::cout << "Calling Circle Constructor\n"; };
~Circle(){ std::cout << "Calling Rectangle Destructor\n\n"; };
virtual void draw() const{ /* Draw Circle*/ };
virtual void doSomething1(int) const { /* doSomething1 */};
virtual void doSomething2(int, float) const { /* doSomething2 */};
private:
int r;
};
class ShapeFactory{
public:
ShapeFactory(int = 0, double = 0);
std::unique_ptr<Shape> CreateShape(const std::string & );
~ShapeFactory();
};
std::unique_ptr<Shape> ShapeFactory::CreateShape(const std::string & type /*, int rad, int side1, int side2, .... */) {
if ( type == "circle" ) return std::unique_ptr<Shape>(new Circle( /* rad */)); // Should call Circle(int rad)!
if ( type == "rectangle" ) return std::unique_ptr<Shape>(new Rectangle( /* side1, side2 */)); // Should call Rectangle(int, int)!
// if ( type == "someNewShape") return std::unique_ptr<Shape>(new someNewShape( /* param1, param2, ... */)); // Should call someNewShape(param1, param2)!
throw std::invalid_argument("MobileFactory: invalid type: " + type);
}
У меня также есть еще одно сомнение. Представьте, что из-за каких-то нужд мне нужны члены класса для класса "ShapeFactory". То, что я хотел бы сделать интуитивно, выглядит примерно так:
std::vector< std::unique_ptr<ShapeFactory2> > mylist;
mylist.push_back( new ShapeFactory2(CreateShape("circle",radius), param1, param2) );
mylist.push_back( new ShapeFactory2(CreateShape("rectangle",side1,side2), param1, param2) );
for (std::vector< std::unique_ptr<ShapeFactory2> >::const_iterator it = v.begin(), end = v.end(); it != end; ++it)
{
int param1 = it->param1;
float param2 = it->param2;
it->doSomething2(param1, param2);
// or equivalently
Shape * myShape = *it;
int param1 = it->param1;
float param2 = it->param2;
myShape->doSomething2(param1, param2);
}
Как изменится объявление класса ShapeFactory для этого конкретного случая? Буду ли я теперь иметь smart_pointer в качестве члена класса, кроме param1, param2? Если да, может ли кто-нибудь проиллюстрировать, как реализовать конструкторы/деструкторы?
Приветствуются все предложения/идеи! ;-)
Fitter
, производные классы —DisjointFitter
иJointFitter
. Идея состоит в том, чтобы инкапсулировать параметры для создания объектов в классе с именемData
, верно? Что касается второй части моего поста, как будет выглядеть дизайн класса Abstract Factory? 27.11.2011doSomething1
на самом деле являетсяconvolution
, аparam1
— полосой изображения. Какие-либо предложения? 27.11.2011filterBank.push_back(new FilterBankElement(Kernel2D<float>(createGaussian(sigma)), imageBand) )
. У меня есть этот классFilterBankElement
, где я хотел бы иметь указатель на конкретное ядро, чтобы, когда я это делаю,filterBank[0]->convolve(image, filterBank[0]->imageBand)
выбирался правильный методconvolution
в зависимости от типа фильтра. 27.11.2011