关于纯抽象类中的静态成员函数-设计模式

about static member functions in pure abstract classes - design pattern?

本文关键字:函数 设计模式 静态成员 于纯 抽象类      更新时间:2023-10-16

我最近发现了一个在pure abstract classes中使用static member functions初始化指向其派生类对象的指针的示例。我想知道,这是一种设计模式,还是一种良好的编程实践?下面的代码只是一个示例(例如defineRectangle() and defineCircle()成员功能):

class Shape;
typedef std::unique_ptr<Shape> shape_ptr;
class Shape{
    public:
        Shape(){};
        virtual ~Shape(){};
        virtual void draw() const = 0;
        virtual float area() const = 0;
        virtual shape_ptr clone() const = 0;
        virtual shape_ptr create() const = 0;
        static shape_ptr defineRectangle(int, int );
        static shape_ptr defineCircle(float);
};
shape_ptr Shape::defineRectangle(int height, int width){
    shape_ptr ptrRectangle = shape_ptr(new Rectangle(height, width));
    return (ptrRectangle);
}
shape_ptr Shape::defineCircle(float radius){
    shape_ptr ptrCircle = shape_ptr(new Circle(radius));
    return (ptrCircle);
}

最终目标是定义一个derived classes的容器。例如:

std::vector<std::unique_ptr<Shape> > vect;

然后我们可以通过调用Shape类的静态成员函数在容器中添加派生类:

vect.push_back(Shape::defineCircle(10));
vect.push_back(Shape::defineRectangle(5, 4));

或直接无任何接口:

vect.push_back(std::unique_ptr<Shape>(new Circle(10)));
vect.push_back(std::unique_ptr<Shape>(new Rectangle(5,4)));

在容器中添加派生类的两种方式中,哪一种应该是首选,为什么
完整的代码可以在以下链接中找到
上面的任何灯都非常受欢迎;-)

我想知道,这是一种设计模式,还是一种良好的编程实践?

是的,这是工厂模式的变体。

基本上,它允许您拥有一个单独的方法,该方法将根据该方法的参数来调度正确派生对象类型的动态创建。这允许您在代码中使用相同的"工厂"函数,如果对工厂方法创建的底层对象有任何更改或添加,则不必更改实际调用"工厂"功能的代码。因此,它是一种封装形式,将对象创建的任何更改隔离到"工厂"后面的代码段,而不是调用"工厂"的代码。例如,使用工厂,添加工厂方法可以创建的新类型相对简单,但调用工厂的以前代码都不必更改。您只需要为要创建的新对象创建一个新的派生类,对于任何需要该新对象的新代码,都需要传递正确的新参数。所有旧的参数仍然有效,并且代码中不需要对返回的指针类型等进行更改。

在工厂中使用智能指针的原因是为了避免指针所有权不明确时可能发生的内存泄漏。例如,工厂必须返回一个指针,因为它正在动态地创建对象。然后问题就变成了谁清理指针以避免悬挂指针或内存泄漏?智能指针解决了这个所有权问题,并保证当其他对象仍指向内存时,内存不会被无意中清理干净,或者内存不会因为指向该内存位置的最后一个指针超出范围而丢失,而没有调用delete

我建议不要将工厂方法放在基类中,因为从技术上讲,ShapeRectangleCircle一无所知。如果您添加一个新形状,例如Donut,那么您会怎么做?在Shape中添加新的工厂方法?你很快就会把界面弄得一团糟。因此,国际海事组织认为,第二种方法会更好。

如果您想减少每次创建shape_ptra的繁琐程度,您可以始终将工厂方法移动到适当的子类:

class Circle : public Shape
{
    // ...
public:
    static shape_ptr make(float radius) 
    { 
        return shape_ptr(new Circle(radius)); 
    }
};
// ...
vect.push_back(Circle::make(5.0f));

由于有std::unique_ptr,我假设编译器支持C++11。在这种情况下,让我提供第三种选择:

vect.emplace_back(new Circle(10));
vect.emplace_back(new Rectangle(5,4));

(关于.emplace_back:push_back vs template_back)

这样就不需要重复shape_ptr,也不需要在添加新子类时向Shape声明新的工厂方法。


编辑:在C++14中,可以使用std::make_unique来摆脱原始的new调用。

vect.emplace_back(std::make_unique<Circle>(10));
vect.emplace_back(std::make_unique<Rectangle>(5, 4));