使用预先填充的对象映射实现工厂模式

时间:2014-05-07 11:27:18

标签: c++ factory smart-pointers

我有一个将字符串ID映射到base_object的特定实现的映射。 任何base_object都有一个方法get_id,它返回对象的id。 然后我使用(伪)

填充地图
void addToMap(base_object* obj){
make_pair(obj->get_id(),obj);
}

此地图的作用类似于工厂,并且知道使用id返回正确的对象。这是检索特定对象的方法声明:

base_object* get(string id);

所有对象都没有字段,只有多态方法对每个实现都有不同的行为。

我不确定实现此目的的最佳方法是什么。

地图应该是<string,unique_ptr<base_object>>的地图吗? 在这种情况下,当我使用get返回base_object时,是否可以返回指向base_object的原始指针? (我知道地图会继续生存,以免物体被毁坏?) 或者在这种情况下我应该使用shared_ptr? 此外,由于对象实际上没有任何字段,可能最好返回对象的副本吗?

无论如何,我认为它看起来像是一个糟糕的设计,我无法决定解决这个问题的最佳方法。 我对cpp很新,所以我不太熟悉指针的所有差异和最佳用法......

4 个答案:

答案 0 :(得分:1)

您可以使用std::unique_ptr<base_object>并将const引用返回unique_ptr

可能的实施:

struct Data
{
    std::map<std::string,std::unique_ptr<base_object>> data;

    void add(base_object* obj){
        data[obj->get_id()] = std::unique_ptr<base_object>(obj);
    }

    const std::unique_ptr<base_object>& get(const std::string& id) {
        return data.at(id);
    }
};

用例示例:

Data data;
data.add(new test1_object{});
data["test1"]->create(); // call a virtual function of base_object

请注意,这不是真正的工厂。如果base_object的抽象函数应该负责创建您的实际产品,您可以这样做:

struct Factory
{
    std::map<std::string,std::unique_ptr<base_object>> workers;

    void add(base_object* obj){
        data[obj->get_id()] = std::unique_ptr<base_object>(obj);
    }

    Product create(const std::string& id) {
        return data.at(id)->foo(); // call the virtual function here
    }
};

Factory factory;
factory.add(new test1_object{});
Product x = factory.create("test1");

答案 1 :(得分:1)

使用unique_ptr<base_object> const &。这向调用者发出信号,告知它获取的是具有所请求id的唯一对象的句柄。使用shared_ptr信号表明它可能负责保持对象存活。

此外,不需要map:您可以根据ID使用订单/哈希的setunordered_set。这样,您就不必两次存储ID。

(你正在实施的东西更像是一个对象池,而不是一个工厂。)

答案 2 :(得分:0)

工厂模式的标准未在启动时填充对象。根本没有任何物品。工厂只知道如何创建新对象。一个可能的实现可以使用地图和注册的静态执行此操作!类的方法(不是对象)。

工厂应始终返回一个新实例,而不是引用或指向已存在对象的指针。应用程序通常不知道如何销毁这种特殊类型的副本而不是自己的实例。

答案 3 :(得分:0)

如何最好地设计您的东西取决于用例和设计约束:

  • 如果您可以保证返回的对象足够长并且您可以保证您将返回实际对象,则最好通过引用返回(如果没有要返回的对象,则有例外。在适当的地方使用)。
  • 如果您可以保证返回的对象足够长如果有要返回的对象,则只返回原始指针。
  • 如果所有的地图元素都应该存在于程序的末尾,请不要让地图拥有它们,除非它存在的时间很长并且你想强制它清理它们:静态地或动态地分配它们(在第二个例如,您可能希望在std::atexit注册它们以进行清理),并让地图只保留一个非拥有的原始指针。
  • 如果您的程序在没有RTTI的情况下编译并且每个对象都是其类的单例,请考虑使用typeid作为密钥(至少是名称字段)而不是自定义字符串。
  • 无论如何,你后来说这些对象唯一有趣的地方就是一种方法:为什么不用std::function来获得最大的灵活性?
  • std::unordered_map已分摊O(1)访问权限,仅std::map O(ln(n))。