缔冠期刊网

C++ll实现可变参数泛型抽象工厂

2022-06-09

1 引言(Introduction)

一种设计模式就是解决某一类软件设计问题的可复用的解决方案。设计模式的实现技术主要是多态,包括动多态和静多态。起先使用动多态,动多态是通过继承和虚函数实现,在运行期间,通过虚函数调用不同子类的虚成员函数来实现不同的功能。动多态的绑定是入侵性、插入式的,实现代价较高。静多态是通过模板编程实现的,通过在编译期间接口绑定不同的功能代码来实现多态。传统的静多态可以在一定程度上提供非入侵性、非插入式的实现,降低实现代价。但是,当具体产品构造函数参数不同、需要异类组合、具体产品数量繁多时,传统的动多态和静多态实现起来都很繁琐、很困难、复用性很低。

随着技术的发展,在模板编程的基础上进一步发展出泛型编程技术,并在C++标准库(STL)和实际工程中得到广泛应用[1]。针对设计模式传统实现方式存在的问题,本文以抽象工厂模式为例,通过C++11新标准泛型编程技术,给出一种可变参数泛型抽象工厂的实现方式。

2 抽象工厂模式(Abstract factory pattern)

抽象工厂模式属于创建型模式,其设计动机是:提供一个接口,让该接口负责创建一系列“相关或者相互依赖的对象”,用户无需指定工厂和产品的具体的类型、无需了解它们的具体实现,从而绕过常规的对象创建方式。

抽象工厂模式结构如图1所示,抽象工厂将工厂和产品全部抽象化,一个抽象工厂可以生成一组抽象产品,而一个具体工厂则生成一个系列具体产品的特定组合[2]。AbstractFactory定义抽象工厂生成的一组抽象产品的接口,AbstractProductA、AbstractProductB定义某一种抽象产品的接口;具体工厂ConcreteFactory1负责创建1系列具体产品类型ProductA1、ProductB1的组合,具体工厂ConcreteFactory2负责创建2系列具体产品类型ProductA2、ProductB2的组合,依此类推。

对象创建时,用户先创建具体工厂ConcreteFactory1或ConcreteFactory2类的对象,再用ConcreteFactory1创建1系列具体产品类型的组合,或用ConcreteFactory2创建2系列具体产品类型的组合。

 

 

 

 

 

 

 

图1 抽象工厂模式结构图

Fig.1 Structure chart of abstract factory pattern

3 泛型编程实现抽象工厂(Implement abstract

factory by generic programming)

抽象工厂传统实现方式的主要弱点是类型繁琐、类型依赖性强、可复用性弱。一个抽象工厂往往是为某一特定需求而设计,一般不能在其他场合复用。还有尽管抽象工厂可以将具体产品的创建委派给特定类型的工厂,但这种委派需要通过纯代码方式实现,没能充分利用语言所提供的抽象特性。

在设计模式的实现技术中,泛型编程能够提高编程效率、实现非侵入性实现,大大提高代码复用率。在泛型的参与下,许多设计可能更为精妙、更加优雅、更具扩展性[3]。面向对象编程(OOP,Object-Oriented Programming)试图将数据和方法封装在一起,各种操作都与数据类型相关。泛型编程(GP,Generic Programming)则试图将数据和方法分离开来,将类型参数化,使得同一种操作可以适用于不同数据类型,C++标准库(STL)就是一种典型应用[4]。

4 C++11实现可变参数泛型抽象工厂(Implement

variable parameter generic abstract factory by

C++11)

通过C++11新标准泛型编程技术,能够实现产品类型可变、参数可变、异类组合的泛型抽象工厂,当你需要特定类型抽象工厂时,可随时复用而无需再定义专门的抽象工厂实现。

4.1 结构图

C++11实现的可变参数泛型抽象工厂结构如图2所示,其完整实现代码附后。

 

 

 

 

 

 

 

 

 

 

 

 

 

图2 C++11实现的可变参数泛型抽象工厂结构图

Fig.2 Structure chart of implement variable parameter

generic abstract factory by C++11

具体实现非常简洁,只包含两个模板类:泛型工厂类GenericFactory、内嵌类具体产品注册类Register。这是基于C++11新标准实现的,必须在支持C++11新标准(2011年ISO发布)的编译器中才能正常编译使用,比如Visual Studio 2013等。

4.2 泛型工厂类GenericFactory

该类是该抽象工厂模式的核心,负责存储管理抽象工厂和各种具体工厂数据、具体产品的创建等工作[5]。在该类右上角的虚线框中,包含三个模板参数:抽象产品类AbsProduct、具体产品类标识KeyConProduct(缺省std::string)、产品类构造函数可变参数列表0—n项...ArgTypes。最后一个模板参数便是C++11支持的可变参数类型,支持可以数目、可变类型的0—n个参数[6],下同。不同种类的抽象工厂无需通过不同的公共基类(即传统抽象工厂中的AbstractFactory)来表达接口的共性,能够很优雅地实现异类集合[7]。

该类通过静态变量和静态函数方式实现简单的单例模式(singleton),各种构造器都是私有的,不允许外部构造。外部只能通过调用静态函数get_Instance获取唯一的静态实例unique_generic_factory。

该类只有一个数据成员mapConFactory,是std::map类型的私有数据成员,用于存放具体产品标识KeyConProduct和具体工厂构造函数指针ConFactoryFun组成的键值对。外部只能通过调用该类的公有函数存取mapConFactory。通过内嵌类Register类的实例化可以将数据存入mapConFactory;Unregister函数可以从mapConFactory中注销数据;getConProduct_shared_ptr、getConProduct_unique_ptr函数可以得到已注册标识为conp的类的一个实例;getSize函数可以得到已注册具体工厂的总数;getKey函数可以得到已注册索引为n的类的具体产品标识,只不过stl::map默认按键值类型自动排序(这里默认按字母顺序),若需要控制排序方式,可以在应用程序中增加一个map<索引号,工厂标识>变量来实现。

4.3 具体产品注册类Register

该类是泛型工厂类GenericFactory的内嵌类,使用内嵌类可明显简化设计。该类作为抽象工厂的原料和接口,用于创建和注册具体工厂,将注册数据存入泛型工厂类的GenericFactory::mapConFactory。在该类右上角的虚线框中,只有一个模板参数:具体产品类ConProduct。

该类很简单,只包括一个构造函数Register和私有静态函数Create_ConProduct(包含可变参数列表)。该类与泛型工厂类GenericFactory的关系也很清晰,只是在创建该类对象时,由其构造函数调用泛型工厂类的GenericFactory::get_Instance函数,将创建具体产品的Create_ConProduct函数指针存入泛型工厂类的GenericFactory::mapConFactory。需要注意的是,该类并不实际创建具体产品对象,具体产品对象的创建,是由用户通过调用泛型工厂类的GenericFactory::getConProduct_shared_ptr、GenericFactory::getConProduct_unique_ptr函数来实现的。

这里由于使用了C++11新标准提供的新技术,使得代码更为精炼、更具扩展性。可变参数类型...ArgTypes使得该接口可以很优雅地支持具体产品类构造函数可变参数列表。智能指针shared_ptr、unique_ptr的使用实现了自动内存管理、无需delete释放内存,share_ptr通过引用计数共享所有权,unique_ptr独享所有权,可根据实际需要选用。使用C++11新特性emplace代替insert向STL容器添加新元素,可以在容器管理的内存中直接构造新元素,省去构造临时对象、减少内存开销,代码更为简洁高效。

5 实际使用(Actual use)

该泛型抽象工厂可以满足抽象工厂、简单工厂、可变参数、异类组合、具体产品数量繁多等情况的实现需求。实际使用很简单,首先创建各种具体工厂,方法就是创建各种具体产品注册类Register对象,将各种具体工厂的函数指针存入泛型工厂类的GenericFactory::mapConFactory。然后,便可以通过泛型工厂类的GenericFactory::get_Instance调用GenericFactory::getConProduct_shared_ptr、GenericFactory::getConProduct_unique_ptr函数来创建各种具体产品对象。可以通过函数封装实现抽象工厂的需要,将一系列相关产品封装在一个函数中,实现一次性创建一系列相关产品的需要。

5.1 具体工厂构造函数的参数可变

比如,现在已定义Shape基类和Square、Circle两个子类,便可以通过下面代码使用该泛型抽象工厂,实现具体工厂的注册和具体产品的创建。Square、Circle两个子类构造函数的参数可变,参数个数、类型都可以各不相同。这里,子类Square的构造函数有三个参数CPoint、CPoint、unsigned,子类Circle的构造函数有两个参数CPoint、int,其结构如图3所示。

 

 

 

 

 

 

 

图3 具体工厂构造函数的参数可变

Fig.3 Parameters of concrete factory constructor

are variable

5.2 具体工厂的异类组合

比如,跨国公司计算不同国家员工工资可能用到异类组合。假设美国员工工资包括奖金Bonus、津贴Subsidy、税收Tax等三个部分,中国员工工资包括奖金Bonus、津贴Subsidy、税收Tax、住房公积金Found等四个部分。使用本文给出的C++11实现的可变参数泛型抽象工厂,通过函数封装不同抽象工厂的需要,便可轻松实现这种异类组合,其结构如图4所示。

 

 

 

 

 

 

图4 具体工厂的异类组合

Fig.4 Heterogeneous combinations of concrete factory

6 泛型抽象工厂完整实现代码(Complete

implementation code of generic abstract factory)

//GenericFactory.h,泛型抽象工厂头文件

#pragma once

#include

#include

#include

 

//泛型工厂类GenericFactory,包含3个模板参数:

//抽象产品类、具体产品类标识的类型、产品类构造函数可变参数列表0-n项

template

class GenericFactory

{

private:

typedef AbsProduct*(*ConFactoryFun)(ArgTypes... args);

typedef std::map

MapConFac;

MapConFac m_mapConFactory;

GenericFactory(){}

GenericFactory(const GenericFactory&)=delete;

GenericFactory(GenericFactory&&)=delete;

GenericFactory operator=(const GenericFactory&

other)=delete;

public:

~GenericFactory(){}

 

//具体产品注册类Register,有1个模板参数:具体产品类。使用内嵌类可明显简化设计

template

class Register

{

public:

Register(const KeyConProduct& conp)

{

GenericFactory::get_Instance()->

m_mapConFactory.emplace(conp,Create_ConProduct);

}

private:

inline static AbsProduct*Create_ConProduct(ArgTypes...args)

{

return new ConProduct(args...);

}

};

bool Unregister(const KeyConProduct& conp)

{

return m_mapConFactory.erase(conp)==1;

}

std::shared_ptrgetConProduct_shared_ptr(const KeyConProduct& conp,ArgTypes...args)

{

if(m_mapConFactory.find(conp)==m_mapConFactory.end())

return std::shared_ptr();

else

return std::shared_ptr(m_mapConFactory[conp](args...));

}

std::unique_ptrgetConProduct_unique_ptr(const KeyConProduct& conp,ArgTypes...args)

{

if(m_mapConFactory.find(conp)==m_mapConFactory.end())

return std::unique_ptr();

else

return std::unique_ptr(m_mapConFactory[conp](args...));

}

unsigned getSize()

{

return m_mapConFactory.size();

}

KeyConProduct getKey(unsigned n)

{

MapConFac::iterator it=m_mapConFactory.begin();

for(inti=0;it!=m_mapConFactory.end();i++,it++)

if(n==i) return it->first;

return KeyConProduct();

}

inline static GenericFactory*get_Instance()

{

static GenericFactoryunique_generic_factory;

return&unique_generic_factory;

}

};

7 优点与缺点(Advantages and disadvantages)

C++11实现的可变参数泛型抽象工厂优点包括:(1)不同种类的抽象工厂无需通过不同的公共基类(也即传统抽象工厂中的AbstractFactory)来表达接口的共性,能够很优雅地实现异类集合;(2)通过C++11很优雅地实现具体产品类构造函数的可变参数列表;(3)通过智能指针shared_ptr、unique_ptr实现自动内存管理,无需delete释放内存;(4)泛型编程在编译期对所有的绑定操作进行检查,具有更好的类型安全性[8];(5)运用C++11新特征和内嵌类使代码更为简洁高效;(6)本文给出的方法及代码具有实用性,可应用到软件项目中,其他相关模式也可参照实现。其缺点是:(1)使用中编译报错时,理解和查错较为困难;(2)实现代码虽小,但生成的执行代码可能较大。实际使用时,可根据其优缺点酌情选择。

8 结论(Conclusion)

综上所述,抽象工厂模式可以通过传统的动多态和静多态实现,也可以通过新兴的泛型和模板实现。抽象工厂模式的传统实现方式在处理具体产品构造函数参数不同、异类组合、具体产品数量繁多的情况时,都显得很繁琐、很困难、复用性很低。针对这一问题,本文以抽象工厂模式为例,应用C++11新标准和泛型编程技术,给出了一种C++11可变参数泛型抽象工厂的实现方式。该方式比传统实现方式更为简洁高效、复用性更强,优雅地实现了对产品类型可变、参数可变、异类组合的支持。

参考文献(References)

[1] Bemardi ML,Cimitile M,Lucca GD.Design pattem detection using a DSL-driven graph matching approach[J].Journal of Software Evolution&Process,2014,26(12):1233-1266.

[2] B Rasool G,Mader P.A customizable approach to design pattems recognition based 011 feature types[J].Arabian Journal for science&Engineering,2014,39(12):8851-8873.

[3] 许涵斌,等.一种基于结构查询的UML设计模式识别方法[J].计算机科学,2014,41(11):50-55.

[4] B Matthew H.Austere(美).侯捷,译.泛型编程与STL[M].北京:中国电力出版社,2003.

[5] BLarman.C.(美).李洋,等,译.UML和模式应用[M].北京:机械工业出版社,2006.

[6] B Michael Wong(加),IBM XL编译器中国开发团队.深入理解C++11:C++11新特性解析与应用[M].北京:机械工业出版社,2013.

[7] B Gamma Erich(美),等.李英军,等,译.设计模式:可复用面向对象软件的基础[M].北京:机械工业出版社,2000.

[8] B Joshua Kerievsky(美).杨光,刘基诚,译.重构与模式(修订版)[M].北京:人民邮电出版社,2013.

作者简介:

闵 军(1966-),男,硕士,研究员.研究领域:C++程序设计,设计模式,计算机网络.

论文中心更多

期刊百科
期刊投稿 期刊知识 期刊审稿 核心期刊目录 录用通知 期刊版面费 投稿期刊推荐 学术问答
基础教育
小学语文 中学语文 小学数学 中学数学 小学英语 中学英语 物理教学 化学教学 生物教学 政治教学 历史教学 地理教学 科学教学 音乐教学 美术教学 体育教学 信息技术 班主任管理 校长管理 幼教 教育管理 微课教学 作文教学 德育教学 教学设计
医学论文
内科医学 外科医学 预防医学 妇科医学 检测医学 眼科医学 临床医学 药学论文 口腔医学 中西医 中医学 外科 护理 基础医学 急救医学 老年医学 医学实验 儿科医学 神经医学 兽医学 肿瘤医学 综合医学
职业教育
教育学原理 电影文学教育 学前教育 教育学管理 高等教育学 教育技术学 职业技术教育 成人教育学 特殊教育学 教育心理学 家庭教育 教育毕业 中专中职教育 教学设计 国学教育 学术研究 大学教育
药学卫生
社区门诊 医药学 医患关系 医院管理 疾病预防 保健医学 公共卫生 医学教育
文科论文
农业经济 工商管理毕业 会计毕业 行政管理 法律毕业 市场营销 经济毕业 汉语言文学 财务管理 物流管理 人力资源 旅游管理 国际贸易 物业管理 新闻学 企业管理 金融银行 社会科学 食品安全 办公档案 审计学 税务税收学 外国文学 哲学
理科论文
机电毕业 土木工程 计算机毕业 电气毕业 建筑毕业 电子商务 工程毕业 设计毕业 机械制造 汽车毕业 园林毕业 农学毕业 数控毕业 软件技术 水利工程 环境生态 畜牧渔业 化工毕业 科技创新 石油矿藏
论文格式
开题报告 论文题目 摘要关键词 目录提纲 论文致谢 参考文献 附录其他 论文答辩
职业论文
教育论文 经济论文 科技论文 财会论文 管理论文 医学论文 法学论文 文学论文 工业论文 建筑论文 农业论文 水利论文 计算机论文 社科论文 机械论文 生态环境 中西文化

先发表后付款 不成功可退款

权威机构认证 专注期刊10余年 1000余家杂志社长期合作

缔冠期刊网

首页 网站地图 返回顶部
Copyright © 1998- 缔冠期刊网