C++抽象工厂是否应该为构造对象提供销毁方法

Should C++ abstract factory provide destroy method for constructed objects?

本文关键字:对象 方法 工厂 抽象 是否 C++      更新时间:2023-10-16

考虑以下接口(使用哑指针,因为我们仍在C++98(

class WidgetMaker {
    virtual Widget* makeWidget() = 0;
};

通过以下可能的实现

class SpecificWidgetMaker: public WidgetMaker {
    Widget* makeWidget() {
        return new SpecificWidget();
    }
};
Widget

是一些带有虚拟析构函数的基类,SpecificWidget 扩展了它。我的同事声称WidgetMaker界面应该包含以下方法

virtual void freeWidget(Widget* widget);

理由是,这样我们就不会强制 makeWidget 实现使用标准的新分配,它们可以使用自定义池分配器,或者在 widget 无状态或其他情况下始终返回相同的全局实例。

我觉得这样的设计通常是一个坏主意 - 它使客户端代码复杂化,违反了KISS和YAGNI,使过渡(在未来20年内在我们的组织中不太可能(变得更加困难unique_ptr。我应该相信自己的感觉吗?在什么情况下,自由方法作为抽象工厂接口的一部分是合理的?

你朋友提出的解决方案(实际上,也是你原来的解决方案(的一个问题是它有一个不必要的非平凡协议。一旦你通过 makeWidget 获得一个Widget,你需要记住解除分配它(直接,或者通过调用工厂的某个方法(。众所周知,这是脆弱的 - 它要么会迅速崩溃(导致Widget泄漏(,要么会使客户端代码真正复杂化。

如果你看一下std::shared_ptr::shared_ptr(...)的界面,你可以看到它可以接受一个自定义的删除器对象

因此,也许你可以typedef(或等效的(什么是Widget智能指针:

using WidgetPtr = std::shared_ptr<Widget, ...>

如果您以后决定工厂需要在解除分配Widget时执行某些操作,则可以将typedef更改为使用自定义删除程序的,此自定义删除程序可以通知工厂正在删除对象。

这样做的主要优点是它消除了记住从用户那里解除分配Widget的责任。

我想

说这里没有一般的经验法则。这完全取决于您Widget实施的细节。

如果正确销毁任何Widget子类的实例所需的所有操作都可以在其普通析构函数中处理,则在因子中声明显式freeWidget (( 没有任何用处。它不会增加任何价值。

另一方面,如果需要在析构函数中执行由于某种原因无法处理的事情,那么显然,您需要一个显式方法来销毁您的小部件。

也许目前不需要任何特殊处理,这种处理,但你预见到将来需要它。在这种情况下,声明显式 freeWidget (( 方法是有意义的,以避免以后重写一堆代码。

如果您决定采用 freeWidget (( 方法,您可以考虑做的一件事是将所有子类的析构函数设为私有(最有可能使用一些合适的friend声明,以便某些东西实际上可以破坏这些东西(,以强制执行此策略。

您可能希望显式freeWidget (( 的一个示例是例外。从析构函数中抛出异常是...敏感。这是允许的,但它带有某些...限制。因此,如果销毁小部件可能会引发异常,则在这种情况下,使用 freeWidget (( 将允许您更好地控制引发异常,并在执行此操作之前正确清理已销毁的小部件。