如何在C ++中正确实现工厂

时间:2013-08-08 16:44:37

标签: c++ design-patterns factory factory-pattern

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

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来解决这个问题而且我坚持了下来。我希望所有课程的所有实例都知道哪个工厂正在使用,所以我想出了以下想法,我真的不喜欢它们中的任何一个:

的Singleton

这只是想到了,我很快就杀了这个想法。生成的产品是一个库,一个应用程序可以由许多线程使用不同的设置。我想使用依赖注入。

使用模板(例如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
}

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

0 个答案:

没有答案