我用C++中的一个模板类实现了multiton模式。
#ifndef MULTITON_H
#define MULTITON_H
#include <map>
template <typename Key, typename T> class Multiton
{
public:
static void destroy()
{
for (typename std::map<Key, T*>::iterator it = instances.begin(); it != instances.end(); ++it) {
delete (*it).second;
}
}
static T& getRef(const Key& key)
{
typename std::map<Key, T*>::iterator it = instances.find(key);
if (it != instances.end()) {
return *(T*)(it->second);
}
T* instance = new T;
instances[key] = instance;
return *instance;
}
static T* getPtr(const Key& key)
{
typename std::map<Key, T*>::iterator it = instances.find(key);
if (it != instances.end()) {
return (T*)(it->second);
}
T* instance = new T;
instances[key] = instance;
return instance;
}
protected:
Multiton() {}
virtual ~Multiton() {}
private:
Multiton(const Multiton&) {}
Multiton& operator= (const Multiton&) { return *this; }
static std::map<Key, T*> instances;
};
template <typename Key, typename T> std::map<Key, T*> Multiton<Key, T>::instances;
#endif
使用方法:
class Foo : public Multiton<std::string, Foo> {};
Foo& foo1 = Foo::getRef("foobar");
Foo* foo2 = Foo::getPtr("foobar");
Foo::destroy();
有什么改进的建议吗?
3条答案
按热度按时间vjrehmav1#
1)个人偏好,但我会颠倒模板参数的顺序,并将Key默认为std::string(如果这是您最常用的)
然后你可以这样做:
我觉得这样更好。
2)另外,如果你从来没有传递指针/引用到Multitron(这不会违反模式),你不应该在类中需要一个虚拟析构函数。
3)如果你为你的T* 使用一个更聪明的容器,你可以避免调用Foo::destroy()。像
std::map<Key,boost::shared_ptr<T> >
这样的东西会在静态示例被销毁时销毁所有对象。(如果你关心破坏的顺序,那么你需要一些更聪明的东西--你可以从现有的单例解决方案中改编一些东西,比如phoenix单例等)4)你可以将迭代器改为const_iterators。
5)destroy可能应该清除map,以防止在调用destroy后意外访问无效内存。或者如果你想防止这种情况,你应该抛出一个异常。
6)如果你没有使用多态T,那么你可以使用std::map,你的代码看起来像这样。..
我只能想到这些了。
2skhul332#
一个改进是将
getRef
重写为getPtr
(反之亦然,方向并不像not repeating yourself那么重要):0sgqnhkj3#
看来你做得很出色。
顺便问一句,我可以问你为什么在这里铸造示例(在c风格)吗?
我觉得你直接写会更清楚
此外,由于这篇文章已经有10年的历史了,我用现代c++的方式,使用智能指针,对它进行了一点版本升级。请看一下!
multiton.h
multiton.cpp