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

问题描述 投票:4回答:3

我最近发现了一个在static member functions中使用pure abstract classes来初始化指向其派生类对象的指针的例子。我想知道,如果它是一种设计模式,或者它是一个很好的编程实践?下面的代码只是一个ilustration(例如,两个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)));

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

c++ stl polymorphism static-methods
3个回答
1
投票

我想知道,如果它是一种设计模式,或者它是一个很好的编程实践?

是的,它是factory pattern的变种。

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

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


1
投票

我建议不要将工厂方法放在基类中,因为从技术上讲,ShapeRectangleCircle一无所知。如果添加一个新形状,例如Donut,那么你会做什么?为Shape添加一个新的工厂方法?你很快就会把界面弄得乱七八糟。所以,IMO,第二种方法会更好。

如果你想减少每次都必须创建shape_ptr的冗长,你总是可以将工厂方法移动到适当的子类:

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

// ...

vect.push_back(Circle::make(5.0f));

1
投票

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

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

(关于.emplace_backpush_back vs emplace_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));
© www.soinside.com 2019 - 2024. All rights reserved.