仅在Manager类中创建对象

时间:2014-09-14 14:27:49

标签: c++ templates design-patterns

我想创建一个管理器类,它将管理一种类型的所有创建对象。当然这个类也应该创建这些对象。因此,客户端不允许自己创建对象,但必须始终使用manager类来完成。 此外,客户端可以定义自己的类,这些类将由一个Manager管理。

template<class Type>
class Manager{
  //...
  Type* createInstance(){
    Type* ptr = new Type();
    //do sommething
    return ptr;
  }
};

问题是:如何仅将实例的创建限制为管理器类?

一种可能性是将构造函数声明为private,将Manager类声明为友元类:

class A{
  friend class Manager<A>;
private:
  A(){}
  ~A(){}   
};

由于允许客户端定义自己的类,因此他可以将构造函数声明为public,并且管理器仍然可以正常工作。但是客户端能够创建这些类的实例,而没有经理类见证它,导致框架的不良行为/资源管理。

有没有办法克服这个问题?

2 个答案:

答案 0 :(得分:2)

这类经理通常是一个糟糕的模式。以下代码示例说明了原因。

与所有析构函数都应该是虚拟的问题相同。我使用Manager创建一个B,它派生自A,将对象分配给A *指针。如果它被摧毁,它会通过Manager :: destroy(),因为它是通过Manager :: make()

创建的,所以它可能不会很好地结束
#include <iostream>
using namespace std;

template<class Type>
class Manager
{
public:
    Manager(char *type)
    {
        mytype = type;
    }
    Type *make()
    {
        Type *ptr = new Type();
        cout << "in Manager<" << mytype << ">::make() ptr->mytype is " << ptr->mytype << endl;
        return ptr;

    }
    void destroy(Type *ptr)
    {
        cout << "in Manager<" << mytype << ">::destroy() ptr->mytype is " << ptr->mytype << endl;
        delete ptr;
    }
private:
    char *mytype;
};

class A
{
friend class Manager<A>;
protected:
    A()
    {
        mytype = "A";
        cout << "in A()" << endl;
    }
    virtual ~A()
    {
        cout << "in ~A() mytype is " << mytype << endl;
    }
    char *mytype;
};

class B : public A
{
friend class Manager<B>;
protected:
    B()
    {
        mytype = "B";
        cout << "in B()" << endl;
    }
    virtual ~B()
    {
        cout << "in ~B() mytype is " << mytype << endl;
    }
};

int main()
{
    Manager<A> ma("A");
    Manager<B> mb("B");

    B *b = mb.make();
    A *a = b;

    ma.destroy(a);  // This line calls Manager<A>::destroy.  It should call Manager<B>::destroy.

    return 0;
}

产生以下输出:

in A()
in B()
in Manager<B>::make() ptr->mytype is B
in Manager<A>::destroy() ptr->mytype is B    -- Oops - wrong destroy.
in ~B() mytype is B
in ~A() mytype is B

这反过来意味着你不能使用继承来实现它的全部功能,这实际上首先违背了使用OO语言的目的。

根据您认为需要经理的原因,可能有更好的解决方案。

如果它用于内存管理(不太可能是原始代码段),覆盖new和delete值得一看。

如果它是为了跟踪所有用于处理目的的实例(例如游戏中每个游戏滴答更新的对象)那么虽然它有点精神换档,但更好的解决方案是集成管理器进入类本身,作为一组静态成员函数和变量。这类经理几乎总是单身,所以让他们成为静态成员/函数会让你在语义上到达同一个地方。

所以你可能有:

static set<A *> s_collection;

static void Heartbeat()   // in class A
{
    // lock s_collection here
    for (auto it = s_collection.begin, end = s_collection.end() it != end; ++it)
    {
        // process *it
    }
    // unlock s_collection here
}

然后在A :: A()期间将其插入到s_collection中,同样在A ::〜A()期间将其删除。

如果您已经多线程,请小心使用合适的同步原语,因为大多数stl容器本身并不是线程安全的。

答案 1 :(得分:1)

您可以使用密钥模式的某些变体来实现此目的:

http://coliru.stacked-crooked.com/a/257860767a74a15e