我有以下问题:我正在解析包含包含原子的集合的文件(最小的牢不可破的信息)。主要代表:
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类型。 Atom类型设置一次,永远不会更改。
我已经决定使用Factory pattern来解决这个问题而且我坚持了下来。我希望所有课程的所有实例都知道哪个工厂正在使用,所以我想出了以下想法,我真的不喜欢它们中的任何一个:
这只是想到了,我很快就杀了这个想法。生成的产品是一个库,一个应用程序可以由许多线程使用不同的设置。我想使用依赖注入。
使用模板(例如Set<class Factory>
和File<class Factory>
都不是一个选项......将来有些新的Atom实现可能来自用户(外部库)。
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
}
所以这些是我的想法,你怎么看?你有什么经历?最好的方法是什么?