c++ - 如何改进我的简单工厂模式?
问题描述
现在我使用单例工厂来创建对象。我最初想注册每个新类,所以我不需要更改现有的工厂类,但我现在将 CproductA 类公开给用户。我该如何设计它?
有以下三个问题:
- CProductA 类和 CProductB 类向用户公开。
- 我需要提前创建对象。
- 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);
}
解决方案
我重新审视了工厂方法模式,发现我的怀疑是合理的:
工厂模式是指通过某种标识来创建一个注册类的实例。OP 只是将标识符(索引)映射到存储对象的方法调用。
我稍微修改了 OP 的示例:
#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; }
然后是一些应在工厂创建的产品:
// 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>);
}
最后是使用工厂产品的应用程序:
// 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()
关于 OPs 的具体问题:
- CProductA 类和 CProductB 类向用户公开。
不必要。想象后面的部分// factory
是一个库,后面的部分是// products
另一个库。应用程序(之后的第三部分// application
)不需要“知道”任何// products
except void initProducts()
。因此,其他所有内容都不需要从库中导出。
这对于某种插件实现来说甚至是好的。
- 我需要提前创建对象。
不,在我的实现中,只需要一个创建函数。
- m_Map 需要是一个全局变量。
如果工厂实现为单例,则它必须是全局的。这对应用程序程序员来说可能很方便,在这种和类似的情况下我更喜欢这样做。
同样,CFactory
可能会被实例化为非全局的。但是,在创建工厂之后,也必须注册要创建的类(在我的情况下调用initProducts()
)。这就是为什么我之前说过为工厂提供单例可能很方便(对于应用程序开发人员)。
笔记:
为了将创建函数存储在 中CFactory
,我使用了函数指针CProduct* (*pFunc)()
——一个指向函数的指针,没有任何参数,返回指向 的指针CProduct
。或者,我可以使用std::function<CProduct*()>
(并且在生产代码中,我可能使用过)。虽然函数指针可能只针对普通函数(在此示例中就足够了),但std::function
可能针对具有该签名的任何可调用对象,包括仿函数和捕获 lambda。在我们的生产代码中,这显示出很有价值,因为我们生产的一些对象依赖于额外的参数,这些参数必须在工厂的类注册中绑定。
推荐阅读
- c# - 如何使用贝叶斯服务器为动态贝叶斯网络中的变量指定初始概率值
- encryption - 使用 JetBrains Exposed 时加密字段
- javascript - Json 数据未呈现到 DOM
- r - 在列中拆分字符串并在 R 中添加重复的行
- generics - Kotlin out-projected type prohibits the use
- api - 网址格式:
- sublimetext3 - 如何使 sublime 换行支持半角和全角字符?
- django - Apache、Gunicorn 和 Django 的服务器错误
- python - 为什么我们需要在实例尚未创建时在 __init__ 构造函数中指定 self ?
- java - Java继承是不是抄了Super内容?