1

我有以下问题:我正在解析包含包含原子的集合(最小的牢不可破的信息)的文件。主要表现为:

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
}

所以这些是我的想法,你怎么看?你有什么经验?最好的方法是什么?

4

0 回答 0