设计模式里,工厂模式是一类创建型的设计模式。为遵循软件设计和开发的开闭原则,先后衍生出了简单工厂模式,工厂方法模式和抽象工厂模式。作为一种创建型的设计模式,工厂模式是用来创建新对象的。那么问题就来了,以C++为例,C++的类明明构造函数也可以创建新的对象啊,为什么非得引入工厂模式呢?
如果使用C语言,分配并初始化的工作包括:
好像有点麻烦,分配内存、类型转换、初始化。如果是C++,new的动作包括分配内存和调用构造函数两个步骤,比较简化了。这是对一般的初始化过程比较简单的对象。那如果初始化过程比较复杂呢?什么叫比较复杂的初始化过程呢?就是说创建对象不仅是分配内存空间,还要做一些其他初始化工作,甚至是与外部变量或者资源相关的工作。
下面的代码是NVDLA的compiler的源码中的一部分:
SDPScaleOpNode* NodeFactory::newSDPScaleOpNode
(
ScaleNode* origCanNode,
Graph* engGraph
)
{
B b;
DD dd;
NvU16 numBatches = engGraph->profile()->multiBatchSize();
b = dd = new SDPScaleOpNode(origCanNode, numBatches);
dd->setName(std::string("sdp-scale-") + toString(s_sdp_scale_priv.size()));
dd->setId(engGraph->nextNodeId());
dd->setGraph(engGraph);
engGraph->insertNode(b);
s_sdp_scale_priv.insert(std::pair<B, DD>(b, dd));
return dd;
}
我删去了部分代码以便于观察。该接口是要创建一个SDPScaleOpNode,但封装在NodeFactory的newSDPScaleOpNode()接口里。该接口里除了
new SDPScaleOpNode(origCanNode, numBatches);
以外,还有其他setter和insert工作。如果不用工厂模式封装,则每创建一个node,都要在创建node的地方写上其他setter和insert的代码,不便于阅读,而且造成代码冗余。
下面代码是tensorflow源码中的一个片段。可以看到,创建device的初始化过程更加复杂,甚至还可以处理一些异常。
std::unique_ptr<Device> DeviceFactory::NewDevice(const string& type,
const SessionOptions& options,
const string& name_prefix) {
auto device_factory = GetFactory(type);
if (!device_factory) {
return nullptr;
}
SessionOptions opt = options;
(*opt.config.mutable_device_count())[type] = 1;
std::vector<std::unique_ptr<Device>> devices;
TF_CHECK_OK(device_factory->CreateDevices(opt, name_prefix, &devices));
int expected_num_devices = 1;
auto iter = options.config.device_count().find(type);
if (iter != options.config.device_count().end()) {
expected_num_devices = iter->second;
}
DCHECK_EQ(devices.size(), static_cast<size_t>(expected_num_devices));
return std::move(devices[0]);
}
统一创建对象的接口命名
有了上面的例子,也就比较好理解“统一接口命名”了。
如果有工厂模式做封装,那么就成了
createFootball();
createBasketball();
createVolleyball();
createAbcdEfgHijkOpq1234567();
接口命名很清晰,并且能够通过函数名大概知道它的作用。
对象是否真的需要“创建”?
每次new,都会去分配内存(不谈placement new)。但是有的场景下,我们真的需要每次都分配内存吗?要从线程池里获取一个线程,要从内存池里获取一片内存,要从某个资源池里获取一个资源,这些资源本身就有,不需要重新分配,除非池里的资源也用完了。所以工厂模式的另一个作用是,掌控某些资源分配的时机,当真正需要分配内存的时候,才去分配。
工厂模式结合多态,定义一个用于创建对象的接口,但是让子类决定将哪一个类实例化,增加代码的灵活性。比如下列代码,通过一个统一的接口getSportProduct(),运行时可创建出不同的产品。
int test()
{
AbstractFactory *fac = NULL;
AbstractSportProduct *product = NULL;
fac = new BasketballFactory();
product = fac->getSportProduct();
fac = new FootballFactory();
product = fac->getSportProduct();
fac = new VolleyballFactory();
product = fac->getSportProduct();
// other work
return 0;
}
扫码关注腾讯云开发者
领取腾讯云代金券
Copyright © 2013 - 2025 Tencent Cloud. All Rights Reserved. 腾讯云 版权所有
深圳市腾讯计算机系统有限公司 ICP备案/许可证号:粤B2-20090059 深公网安备号 44030502008569
腾讯云计算(北京)有限责任公司 京ICP证150476号 | 京ICP备11018762号 | 京公网安备号11010802020287
Copyright © 2013 - 2025 Tencent Cloud.
All Rights Reserved. 腾讯云 版权所有