Tin*_*Tin 5 c++ polymorphism abstract-class design-patterns smart-pointers
我最近听说过抽象工厂模式,目前在需要参数化构造函数时如何设计这种模式存在一些疑问.
更确切地说,根据我的理解,这种设计模式的主要好处之一是促进代码管理,因为无论何时向系统引入新类型,都需要调整一个工厂函数,其中调用对象构造函数.
我发现的大多数示例都只考虑空构造函数(比如默认构造函数).
但是,如果需要使用参数化构造函数会发生什么?这种设计模式是否仍然有效?
由于参数在派生类之间的类型和数量可能不同,是否需要考虑几个工厂函数?下面我举例说明我想要实现的目标.请注意,为了减少代码行,我只考虑了每个类的一个构造函数,它们既可以作为默认构造函数,也可以作为参数化构造函数.
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);
}
Run Code Online (Sandbox Code Playgroud)
我还有另一个疑问.想象一下,由于某些需要,我需要"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);
}
Run Code Online (Sandbox Code Playgroud)
对于这种特定情况,'ShapeFactory'类声明将如何改变?我现在除了param1,param2之外还有一个smart_pointer作为类成员吗?如果是,是否有人可以说明如何实施构造函数/析构函数?
所有的建议/想法都非常受欢迎!;-)
仅当派生对象的签名足够相似以支持公共构造函数签名时,工厂模式才真正适用。这是一种常见情况,因为对象都适合共享虚拟函数签名,因此构造函数也类似。在您的示例中,从中心点和区域构造形状将适合工厂模式。
如果构造函数根本不相似,那么工厂模式就毫无意义,应该避免。当不使用工厂时,您提供的使用示例更加清晰和安全。
我将为您提供一个关于合理工厂的简短示例,其中包含我最近的代码中的参数:假设您想要将函数拟合到图像的像素。有两种可能的计算方式:不相交(行和列彼此分开)和联合。不相交拟合更便宜,但对于某些数据来说是不可能的。这些计算方式由两个不同的类(DisjointFitter 和 JointFitter)支持,它们接收数据作为参数,并且都派生自 Fitter。工厂的样子:
std::auto_ptr<Fitter> Fitter::create( const Data& data ) {
if ( data.supports_disjoint_fitting() ) {
return std::auto_ptr<Fitter>( new DisjointFitter(data) );
} else {
return std::auto_ptr<Fitter>( new JointFitter(data) );
}
}
Run Code Online (Sandbox Code Playgroud)
从形状的角度来看,它可能看起来像:
enum BasicShape { Round, Edgy };
mylist.push_back( ShapeFactory::CreateShape( Round, 16 ) );
Run Code Online (Sandbox Code Playgroud)
抽象工厂方法如下所示:
static std::unique_ptr<Shape> CreateShape(BasicShape shape, double area) {
if ( shape == Round )
return std::unique_ptr<Shape>( new Circle( sqrt(area / M_PI) ) );
else
return std::unique_ptr<Shape>( new Square( sqrt(area) ) );
}
Run Code Online (Sandbox Code Playgroud)