首页 > 解决方案 > 工厂内专力级施工

问题描述

我想知道是否有人知道强制类层次结构只能由工厂构造的方法,从而有效地禁止在std::make_shared该工厂之外直接使用。

在下面的示例中,我将Node作为基类,将SceneNode作为众多派生类之一。Node包含一个静态成员函数create(),它应该是工厂,并且是创建Node派生类的新实例的唯一方法。

#include <iostream>
#include <memory>

class Node {
  public:
    template <class T, class... Args>
    static std::shared_ptr<T> create(Args&&... args)
    {
      static_assert(std::is_base_of<Node, T>::value, "T must derive from Node");
      std::shared_ptr<T> node = std::make_shared<T>(std::forward<Args>(args)...);
      return node;
    }

  protected:
    Node() {}

};

class SceneNode : public Node {
  public:
    SceneNode() : Node()
    {
    }
};

int main() {
    auto a = Node::create<SceneNode>(); // Should be the only way
    auto b = std::make_shared<SceneNode>(); // Should be forbidden
}

标签: c++factory-pattern

解决方案


使您的工厂成为唯一能够实例化给定类的类的经典方法是使您的类构造函数私有,并使您的工厂成为您的类的朋友:

class Foo
{
    friend class FooFactory;

private:
    Foo() = default;
};

class FooFactory
{
public:
    static Foo* CreateFoo() { return new Foo(); }
    static void DestroyFoo(Foo* p_toDestroy) { delete p_toDestroy; }
};

int main()
{
    // Foo foo; <== Won't compile
    Foo* foo = FooFactory::CreateFoo();
    FooFactory::DestroyFoo(foo);
    return 0;
}

编辑(有一些继承):

#include <type_traits>

class Foo
{
    friend class FooBaseFactory;

protected:
    Foo() = default;
};

class Bar : public Foo
{
    friend class FooBaseFactory;

protected:
    Bar() = default;
};

class FooBaseFactory
{
public:
    template <typename T>
    static T* Create()
    {
        static_assert(std::is_base_of<Foo, T>::value, "T must derive from Foo");
        return new T();
    }

    template <typename T>
    static void Destroy(T* p_toDestroy)
    { 
        static_assert(std::is_base_of<Foo, T>::value, "T must derive from Foo");
        delete p_toDestroy;
    }
};

int main()
{
    // Foo foo; <== Won't compile
    Foo* foo = FooBaseFactory::Create<Foo>();
    FooBaseFactory::Destroy<Foo>(foo);

    // Bar bar; <== Won't compile
    Bar* bar = FooBaseFactory::Create<Bar>();
    FooBaseFactory::Destroy<Bar>(bar);
    return 0;
}

推荐阅读