如何改善我的简单工厂模式? [英] How can I improve my simple factory pattern?

查看:79
本文介绍了如何改善我的简单工厂模式?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

现在,我使用单例工厂创建对象。我本来想向每个新班级注册,所以不需要更改现有的工厂班级,但是现在我向用户公开了CproductA类。我该如何设计?

Now I use a singleton factory to create objects. I originally wanted to register with each new class, so I don't need to change the existing factory class, but I am now exposing Class CproductA to the user. How do I design it?

Coliru查看者

有以下三个问题:


  1. 类CProductA和类CProductB暴露给用户。

  2. 我需要提前创建对象。

  3. m_Map必须是全局变量。



 #include <map>
 #include <iostream>
 using namespace std;

 //Abstract
 class CProduct
 {
  public:
     virtual void Operation() = 0;
 };

 class CProductA:public CProduct
 {
 public:
     virtual void Operation()
     {
        cout << "Operation A" << endl;
     }
 };

 class CProductB:public CProduct
 {
 public:
     virtual void Operation()
     {
        cout << "Operation B" << endl;
     }
 };

 //Simple Factory
 map <int, CProduct*> m_Map;

 class CSimpleFactory
 {
 public:
    void RegisteProduct(int nId, CProduct* pProduct)
    {
       m_Map[nId] = pProduct;
    }
    void CreateProduct(int nId)
    {
       m_Map[nId]->Operation();
    }
    static CSimpleFactory* GetInstance()
    {
       if(m_Instance)
       {
           m_Instance = new CSimpleFactory;
       }
       return m_Instance;
    }
    void Release()
    {
       if(m_Instance)
       {
           delete m_Instance;
       }
    }
 private:
    static CSimpleFactory* m_Instance;
 };

    CSimpleFactory* CSimpleFactory::m_Instance = NULL;


 int main()
 {
     CSimpleFactory* pSimpleFactory = CSimpleFactory::GetInstance();
     pSimpleFactory->RegisteProduct(1,new CProductA);
     pSimpleFactory->RegisteProduct(2,new CProductB);
     pSimpleFactory->CreateProduct(1);
 }


推荐答案

我重新访问了 工厂方法模式 ,发现我的疑问是合理的:

I revisited Factory method pattern and found my doubts reasonable:

工厂模式意味着通过某种标识来创建注册类的实例。 OP只是将标识符(索引)映射到存储对象的方法调用。

The factory pattern means to create an instance of a registered class by a certain identification. OP just maps an identifier (index) to a method call of a stored object.

我对OP的示例进行了一些修改:

I modified OP's sample a bit:

#include <iostream>
#include <map>
#include <string>
#include <vector>

首先输入工厂代码:

// factory

class CProduct {
  protected:
    CProduct() = default;
    virtual ~CProduct() = default;
    CProduct(const CProduct&) = delete;
    CProduct& operator=(const CProduct&) = delete;

  public:
    virtual void operation() = 0;
};

class CFactory {
  public:
    typedef std::string Id;

    static CFactory& get() // Meyers Singleton
    { static CFactory factory;
      return factory;
    }
  private:
    // a table mapping IDs to products
    typedef std::map<Id, CProduct*(*)()> Table;
    Table _table;
  private:
    CFactory() = default;
    ~CFactory() = default;
    CFactory(const CFactory&) = delete;
    CFactory& operator=(const CFactory&) = delete;

  public:
    void registerClass(const Id &id, CProduct*(*pFuncNew)())
    {
      _table[id] = pFuncNew;
    }

    CProduct* create(const Id &id) const
    {
      const Table::const_iterator iter = _table.find(id);
      return iter != _table.end()
        ? (iter->second)() // call function to create instance
        : nullptr; // ERROR! Unknown ID.
    }
};

// helper function template
template <typename CLASS>
CProduct* newProduct() { return new CLASS; }

然后应在工厂中创建一些产品:

then some products which shall be created in factory:

// products

class CProductA: public CProduct {
  public:
    virtual void operation() override
    {
      std::cout << "CProductA::operation()\n";
    }
};

class CProductB: public CProduct {
  public:
    virtual void operation() override
    {
      std::cout << "CProductB::operation()\n";
    }
};

void initProducts(CFactory &factory)
{
  factory.registerClass("A", newProduct<CProductA>);
  factory.registerClass("B", newProduct<CProductB>);
}

最后将工厂与产品配合使用的应用程序:

finally the application which uses the factory with products:

// application

int main()
{
  CFactory &factory = CFactory::get();
  initProducts(factory); // to prevent this call is hard to achieve
  // input sequence
  const std::string input[] = {
    "A", "B", "A", "A", "B", "C"
  };
  // create instances for input by factory
  std::cout << "Create products:\n";
  std::vector<CProduct*> products;
  for (const std::string &id : input) {
    CProduct *const pProd = factory.create(id);
    if (!pProd) {
      std::cerr << "Unknown product type '" << id << "'!\n";
    } else products.push_back(pProd);
  }
  // do something with created products
  std::cout << "Use products:\n";
  for (CProduct *const pProd : products) {
    pProd->operation();
  }
}

输出:

Create products:
Unknown product type 'C'!
Use products:
CProductA::operation()
CProductB::operation()
CProductA::operation()
CProductA::operation()
CProductB::operation()

coliru上的实时演示

关于OP的特定问题:



  1. CProductA类和CProductB类向用户公开。


不一定。想象一下, //工厂之后的部分是一个库, //产品之后的部分是另一个库。该应用程序( //应用程序之后的第三部分)不需要知道任何 //产品除了 void initProducts()。因此,不需要从库中导出其他所有内容。

Not necessarily. Imagine that the part after // factory is one library, the part after // products another library. The application (the third part after // application) doesn't need to "know" anything of // products except void initProducts(). So, everything else doesn't need to be exported from library.

这甚至对某种插件实现都是有益的。

This is even good for some kind of plug-in implementation.



  1. 我需要提前创建对象。


否。在我的实现中,只需要一个create函数。

No. In my implementation, only a create function is needed.



  1. m_Map必须是一个全局变量。


如果工厂实现为单例,则必须是全局变量。对于应用程序程序员而言,这可能很方便,在这种情况下,我还是更喜欢这样做。

It needs to be a global if the factory is implemented as singleton. That might be convenient for an application programmer and I would prefer this in such and similar situations.

CFactory 可能被实例化为非全局实例。但是,在创建工厂后,还要注册要创建的类(在我的案例中,调用 initProducts())。这就是为什么我在(对于应用程序开发人员)为工厂提供单例之前之前说过。

As well, CFactory might be instanced as non-global. However, after creation of factory the registration of classes to create has to happen as well (in my case call of initProducts()). That's why I said before it might be convenient (for the application developer) to provide a singleton for the factory.

注意:

要将创建函数存储在 CFactory 中,我使用了函数指针 CProduct *(* pFunc)()–没有任何参数的指向函数的指针,返回指向 CProduct 的指针。或者,我可以使用 std :: function< CProduct *()> (在生产代码中,我可能有)。尽管函数指针仅可以处理普通函数(在此示例中足够),但 std :: function 可以解决具有该签名的任何可调用对象,包括函子和捕获lambda。在我们的生产代码中,这显示出了宝贵的价值,因为我们的某些生产对象依赖于工厂类注册中必须绑定的额外参数。

To store the creation function in CFactory, I used a function pointer CProduct* (*pFunc)() – a pointer to a function without any arguments returning a pointer to CProduct. Alternatively, I could have used std::function<CProduct*()> (and in production code, I probably had). While the function pointer may address plain functions only (sufficient in this example), std::function might address any callable with that signature, including functors and capturing lambdas. In our production code, this has shown valuable as some of our produced objects depend on extra arguments which have to be bound in class registration of factory.

这篇关于如何改善我的简单工厂模式?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆