我有以下问题:我正在解析包含包含原子的集合(最小的牢不可破的信息)的文件。主要表现为:
class Atom {
// Some data
virtual void Hash(const char *dst); // Calculates checksum of data contained
int Load(std::istream &stream) {} // Do stuff
};
class Set {
std::vector<std::shared_ptr<Atom>> atoms;
// Creates multiple atoms based on data in istream
int Load(std::istream &stream)
{
while(/*...*/){
Atom *atom = new Atom(); // Here's the problematic line
// And I'd like to replace it by factory.Create()
atom->Load(istream);
atoms.push_pack(std::shared_ptr<Atom>(atom));
}
}
};
class File {
std::vector<std::shared_ptr<Set>> sets;
// Loads multiple Sets from istream
int Load(std::istream &stream)
{
while(/*...*/){
Set *set = new Set();
set->Load(istream);
sets.push_pack(std::shared_ptr<Sets>(set));
}
}
};
还有其他几个不重要的类。问题是我有许多不同类型的原子(它们用于生成校验和的哈希类型大多不同),我有这样的东西:
class AtomMd5 : public Atom {
virtual void Hash(const char *dst) {md5(dst, data); }
};
class AtomSha1 : public Atom { /* . . . */ };
class AtomSha256 : public Atom { /* . . . */ };
/* . . . */
并且用户选择应该在整个应用程序中使用哪种Atom 类型。原子类型设置一次并且永远不会改变。
工厂模式
我决定使用工厂模式来解决这个问题,我坚持下去。我希望所有类的所有实例都知道正在使用哪个工厂,所以我想出了以下想法,但我并不喜欢其中的任何一个:
辛格尔顿
这刚刚浮现在脑海中,我很快就扼杀了这个想法。生成的产品是一个库,可由具有不同设置的一个应用程序的多个线程使用。我想使用依赖注入。
既不使用模板,Set<class Factory>
也不File<class Factory>
是一个选项......将来一些新的 Atom 实现可能来自用户(外部库)。
可以在 php/python 中工作,但不能在 C++ 中工作的实现
class AtomFactory {
virtual Atom *Create() {return new Atom(); }
};
class AtomMd5Factory {
virtual Atom *Create() {return static_cast<Atom*>(new AtomMd5()); }
};
/* . . . */
AtomFactory Set::factory; // Added to class
Set::Set(AtomFactory &factory)
{
factory.Create(); // This would work (quite logical)
this->factory = factory; // This would create new Factory with V-Table of AtomFactory,
// not V-Table of AtomMd5Factory (again expected, but won't
// help me)
}
AtomMd5Factory factory;
Set new_set(factory);
使用实现new
这是我考虑过的第一个实际应用程序,它与前一个基本相同,除了*
:
AtomFactory *Set::factory; // Added to class
Set::Set(AtomFactory *factory)
{
factory->Create(); // This would work
this->factory = factory; // This would too
}
但是我不喜欢对堆上的对象进行未跟踪的引用,并且整个实现都在为无效的指针或内存泄漏而尖叫。
使用实现std::shared_ptr
std::shared_ptr<AtomFactory> Set::factory; // Added to class
Set::Set(std::shared_ptr<AtomFactory> &factory)
{
factory->Create(); // This would work
this->factory = factory; // This would too
}
但这不是很多开销吗?我不知道,这对我来说就像是矫枉过正。
仅包含函数指针的容器:
class AtomFactory {
typedef Atom *(*Callback) ();
Atom* Create() { return callback(); }
Callback callback;
};
AtomFactory Set::factory; // Added to class
Set::Set(AtomFactory &factory)
{
factory.Create(); // This would work
this->factory = factory; // This would also work
}
所以这些是我的想法,你怎么看?你有什么经验?最好的方法是什么?