设计模式C++实现 —— 外观模式、组合模式

外观模式应该是用的很多的一种模式,特别是当一个系统很复杂时,系统提供给客户的是一个简单的对外接口,而把里面复杂的结构都封装了起来。客户只需使用这些简单接口就能使用这个系统,而不需要关注内部复杂的结构。DP一书的定义:为子系统中的一组接口提供一个一致的界面, 外观模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。举个编译器的例子,假设编译一个程序需要经过四个步骤:词法分析、语法分析、中间代码生成、机器码生成。学过编译都知道,每一步都很复杂。对于编译器这个系统,就可以使用外观模式。可以定义一个高层接口,比如名为Compiler的类,里面有一个名为Run的函数。客户只需调用这个函数就可以编译程序,至于Run函数内部的具体操作,客户无需知道。下面给出UML图,以编译器为实例。


        相应的代码实现为:

[cpp] view plaincopyprint?
  1. class Scanner  
  2. {  
  3. public:  
  4.     void Scan() { cout<<"词法分析"<<endl; }  
  5. };  
  6. class Parser  
  7. {  
  8. public:  
  9.     void Parse() { cout<<"语法分析"<<endl; }  
  10. };  
  11. class GenMidCode  
  12. {  
  13. public:  
  14.     void GenCode() { cout<<"产生中间代码"<<endl; }  
  15. };  
  16. class GenMachineCode  
  17. {  
  18. public:  
  19.     void GenCode() { cout<<"产生机器码"<<endl;}  
  20. };  
  21. //高层接口  
  22. class Compiler  
  23. {  
  24. public:  
  25.     void Run()   
  26.     {  
  27.         Scanner scanner;  
  28.         Parser parser;  
  29.         GenMidCode genMidCode;  
  30.         GenMachineCode genMacCode;  
  31.         scanner.Scan();  
  32.         parser.Parse();  
  33.         genMidCode.GenCode();  
  34.         genMacCode.GenCode();  
  35.     }  
  36. };  

       客户使用方式:

[cpp] view plaincopyprint?
  1. int main()  
  2. {  
  3.     Compiler compiler;  
  4.     compiler.Run();  
  5.     return 0;  
  6. }  
       这就是外观模式,它有几个特点(摘自DP一书),(1)它对客户屏蔽子系统组件,因而减少了客户处理的对象的数目并使得子系统使用起来更加方便。(2)它实现了子系统与客户之间的松耦合关系,而子系统内部的功能组件往往是紧耦合的。(3)如果应用需要,它并不限制它们使用子系统类。

       结合上面编译器这个例子,进一步说明。对于(1),编译器类对客户屏蔽了子系统组件,客户只需处理编译器的对象就可以方便的使用子系统。对于(2),子系统的变化,不会影响到客户的使用,体现了子系统与客户的松耦合关系。对于(3),如果客户希望使用词法分析器,只需定义词法分析的类对象即可,并不受到限制。

      外观模式在构建大型系统时非常有用。接下来介绍另一种模式,称为组合模式。感觉有点像外观模式,刚才我们实现外观模式时,在Compiler这个类中包含了多个类的对象,就像把这些类组合在了一起。组合模式是不是这个意思,有点相似,其实不然。

      DP书上给出的定义:将对象组合成树形结构以表示“部分-整体”的层次结构。组合使得用户对单个对象和组合对象的使用具有一致性。注意两个字“树形”。这种树形结构在现实生活中随处可见,比如一个集团公司,它有一个母公司,下设很多家子公司。不管是母公司还是子公司,都有各自直属的财务部、人力资源部、销售部等。对于母公司来说,不论是子公司,还是直属的财务部、人力资源部,都是它的部门。整个公司的部门拓扑图就是一个树形结构。

      下面给出组合模式的UML图。从图中可以看到,FinanceDepartment、HRDepartment两个类作为叶结点,因此没有定义添加函数。而ConcreteCompany类可以作为中间结点,所以可以有添加函数。那么怎么添加呢?这个类中定义了一个链表,用来放添加的元素。

       相应的代码实现为:

[cpp] view plaincopyprint?
  1. class Company    
  2. {  
  3. public:  
  4.     Company(string name) { m_name = name; }  
  5.     virtual ~Company(){}  
  6.     virtual void Add(Company *pCom){}  
  7.     virtual void Show(int depth) {}  
  8. protected:  
  9.     string m_name;  
  10. };  
  11. //具体公司  
  12. class ConcreteCompany : public Company    
  13. {  
  14. public:  
  15.     ConcreteCompany(string name): Company(name) {}  
  16.     virtual ~ConcreteCompany() {}  
  17.     void Add(Company *pCom) { m_listCompany.push_back(pCom); } //位于树的中间,可以增加子树  
  18.     void Show(int depth)  
  19.     {  
  20.         for(int i = 0;i < depth; i++)  
  21.             cout<<"-";  
  22.         cout<<m_name<<endl;  
  23.         list<Company *>::iterator iter=m_listCompany.begin();  
  24.         for(; iter != m_listCompany.end(); iter++) //显示下层结点  
  25.             (*iter)->Show(depth + 2);  
  26.     }  
  27. private:  
  28.     list<Company *> m_listCompany;  
  29. };  
  30. //具体的部门,财务部  
  31. class FinanceDepartment : public Company   
  32. {  
  33. public:  
  34.     FinanceDepartment(string name):Company(name){}  
  35.     virtual ~FinanceDepartment() {}  
  36.     virtual void Show(int depth) //只需显示,无限添加函数,因为已是叶结点  
  37.     {  
  38.         for(int i = 0; i < depth; i++)  
  39.             cout<<"-";  
  40.         cout<<m_name<<endl;  
  41.     }  
  42. };  
  43. //具体的部门,人力资源部  
  44. class HRDepartment :public Company    
  45. {  
  46. public:  
  47.     HRDepartment(string name):Company(name){}  
  48.     virtual ~HRDepartment() {}  
  49.     virtual void Show(int depth) //只需显示,无限添加函数,因为已是叶结点  
  50.     {  
  51.         for(int i = 0; i < depth; i++)  
  52.             cout<<"-";  
  53.         cout<<m_name<<endl;  
  54.     }  
  55. };  

         客户使用方式:

[cpp] view plaincopyprint?
  1. int main()  
  2. {  
  3.     Company *root = new ConcreteCompany("总公司");  
  4.     Company *leaf1=new FinanceDepartment("财务部");  
  5.     Company *leaf2=new HRDepartment("人力资源部");  
  6.     root->Add(leaf1);  
  7.     root->Add(leaf2);  
  8.   
  9.     //分公司A  
  10.     Company *mid1 = new ConcreteCompany("分公司A");  
  11.     Company *leaf3=new FinanceDepartment("财务部");  
  12.     Company *leaf4=new HRDepartment("人力资源部");  
  13.     mid1->Add(leaf3);  
  14.     mid1->Add(leaf4);  
  15.     root->Add(mid1);  
  16.     //分公司B  
  17.     Company *mid2=new ConcreteCompany("分公司B");  
  18.     FinanceDepartment *leaf5=new FinanceDepartment("财务部");  
  19.     HRDepartment *leaf6=new HRDepartment("人力资源部");  
  20.     mid2->Add(leaf5);  
  21.     mid2->Add(leaf6);  
  22.     root->Add(mid2);  
  23.     root->Show(0);  
  24.   
  25.     delete leaf1; delete leaf2;  
  26.     delete leaf3; delete leaf4;  
  27.     delete leaf5; delete leaf6;   
  28.     delete mid1; delete mid2;  
  29.     delete root;  
  30.     return 0;  
  31. }  

        上面的实现方式有缺点,就是内存的释放不好,需要客户自己动手,非常不方便。有待改进,比较好的做法是让ConcreteCompany类来释放。因为所有的指针都是存在ConcreteCompany类的链表中。C++的麻烦,没有垃圾回收机制。

        本人享有博客文章的版权,转载请标明出处 http://blog.csdn.net/wuzhekai1985

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/436014.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

rsync的原理和安装使用及配制详解(三)(转)

5、示例脚本 这里这些脚本都是rsync网站上的例子&#xff1a; 1、每隔七天将数据往中心服务器做增量备份 #!/bin/sh# This script does personal backups to a rsync backup server. You will end up# with a 7 day rotating incremental backup. The incrementals will go# in…

单片机c语言控制显示器,单片机实现LCD液晶显示器控制原理..docx

摘 要LCD液晶显示已经是人机界面的关键技术。 本文对基于单片机的LCD夜晶显示器 控制系统进行了研究。首先在绪论中介绍了本课题的课题背景、 研究意义及完成的功能。本系统是以单 片机的基本语言C语言来进行软件设计&#xff0c;51的编程语言常用的有二种&#xff0c;一种是汇…

【转】DCMTK开源库的学习笔记4:利用ini配置文件对dcm影像进行归档

转自&#xff1a;https://blog.csdn.net/zssureqh/article/details/8846337 背景介绍&#xff1a; 医学影像PACS工作站的服务端需要对大量的dcm文件进行归档&#xff0c;写入数据库处理。由于医学图像的特殊性&#xff0c;每一个患者&#xff08;即所谓的Patient&#xff09;…

linux ( )含义,Linux的shell中$()、$[] 、${}分别是什么意思?

在bash中&#xff0c;$( )与 (反引号)都是用来作命令替换的。命令替换与变量替换差不多&#xff0c;都是用来重组命令行的&#xff0c;先完成引号里的命令行&#xff0c;然后将其结果替换出来&#xff0c;再重组成新的命令行。exp 1[rootlocalhost ~]# echo today is $(date &q…

导师评语(转)

星期一到了……小英在交完作业後&#xff0c;中午马上被老师叫去罚站&#xff0c;附加念500遍「我以後不敢编谎话欺骗老师了」。 why&#xff1f;为何这名老师要残忍的对待这名柔弱的小学生&#xff1f;我们来瞧瞧她的作文是怎麽写的…… ━━━━━━━━━━━━━━━━━━…

VxWorks平台下计算cpu的利用率

1、VxWorks的spyLib库提供的spy工具的实现原理。 Spy利用辅助定时器来产生中断&#xff0c;并且为每个任务维护一个计数器。然后记下被中断的任务&#xff0c;并且将该任务的计数器加一。经过一段时间后&#xff0c;每个任务的计数器反映了该任务占用CPU利用率的情况。很明显&a…

【转】DCMTK开源库类继承结构与DICOM3.0标准元素定义的对应关系图

转自&#xff1a;https://blog.csdn.net/zssureqh/article/details/9275271 最近由于课题需要&#xff0c;拿出来一些时间阅读了下DICOM3.0标准。在处理相关的DCM医学图像时使用了DCMTK开源库&#xff0c;废话不多说&#xff0c;直接贴图&#xff1a; 图一&#xff1a;DCMTK开…

c语言中用简易暗纹来输入密码,确定夫琅和费单缝衍射明、暗纹位置的不同教学方法的讨论...

崔红玲苏向英摘要&#xff1a;夫琅和费单缝衍射的明、暗纹位置及相应光强是波动光学中的重要部分&#xff0c;用不同的方法讲解效果不同。本文比较了惠更斯-菲涅耳原理定量积分法及半波带法得到的结论&#xff0c;表明在近似情况下&#xff0c;这两种方法都可以对其进行描述。关…

tickGet

tickGet&#xff08;&#xff09;返回的是从系统启动开始tick计数后的总的tick数目。 tick是啥&#xff0c;是“滴答”&#xff0c;它是一个数值量&#xff0c;本身不能代表时间。 如果说要知道tick增加一个代表多少时间的话&#xff0c;那就要看系统的时钟率了。 在Shell下…

C#控制台程序,发送邮件,可带附件

最近几天由于公司发送了大量内容相同的邮件,而被国外的反垃圾邮件组织列入了黑名单,致使很多客户收不到我们的邮件,客服接到投诉,而之前做的一个查询日志的小页面,因为某种原因,访问速度很慢,甚至这几天人一多,页面就总是超时.刚开始以为是程序问题或者是数据量比较大,但是程序…

【转】从零开始学图形学:10分钟看懂贝塞尔曲线

转自&#xff1a;https://zhuanlan.zhihu.com/p/344934774 引入 在画画的时候&#xff0c;你可能会遇到画曲线的情况。比如你想画一个肥宅的大肚子轮廓&#xff0c;此时你随手一画&#xff0c;发现不好看&#xff0c;感觉太鼓了&#xff0c;于是你只能重新画&#xff0c;再画一…

Linux重启网卡的方法

重启网卡的几种方法&#xff1a;一、network利用root帐户# service network restart二、ifdown/ifup# ifdown eth0# ifup eth0三、ifconfig# ifconfig eth0 down# ifconfig eth0 up

android webview url scheme,Android Webview ERR_UNKNOWN_URL_SCHEME错误

当我点击链接到mailto&#xff1a;adminikiyuzoniki.net时,我收到此错误&#xff1a;net: ERR_UNKNOWN_URL_SCHEME我试图添加一个if(url.startsWith(“mailto&#xff1a;”))条件,但它不起作用.这是我的MyWebViewClient方法&#xff1a;public class MyWebViewClient extends …

【转】编译DCMTK

转自&#xff1a;https://blog.51cto.com/u_2845385/1053291 也许是DCMTK的开发人员认为DCMTK是一个专用的库&#xff0c;没有必要做成动态链接库。 也许是DCMTK的开发人员认为DCMTK需要跨平台&#xff0c;做成动态链接库就平台相关了&#xff0c;违背了跨平台的本意。 …

WinCE6下的kernelIoControl使用方法

WinCE6下的kernelIoControl可不是谁都可以调的。 这个可能很多人曾经知道&#xff0c;但是老是忘记&#xff0c;比如我&#xff0c;哈哈。 kerneliocontrol以前在CE5下面耍惯了&#xff0c;用这个接口&#xff0c;AP简直可以无法无天啊&#xff0c;动不动就reset你&#xff0…

Flex 学习随笔 ---- 使用WebService 与数据库连接

任何一个网络工具&#xff0c; 如果不能和数据打交道&#xff0c;那它就是失败的。 还好Flex是可以的&#xff0c;由于本人刚学&#xff0c;就用asp.netc#来讲下这个简单的连接。 Flex 和数据库通讯现在只能使用Service&#xff0c;如httpservice,rpcservice,webservice等等。 …

第三方登录android代码,Android Learning:微信第三方登录(示例代码)

这两天&#xff0c;解决了微信第三方授权登录的问题&#xff0c;作为一个新手&#xff0c;想想也是一把辛酸泪。我想着&#xff0c;就把我的遇到的坑给大家分享一下&#xff0c;避免新手遇到我这样的问题能够顺利避开。步骤一 微信开发者平台我开始的解决思路是&#xff0c;去这…

【转】基于DCMTK的DICOM相关程序编写攻略

转自&#xff1a;https://blog.csdn.net/jackmacro/article/details/5332654 零、前言&#xff1a; 由于现在的医学影像设备的图像存储和传输正在逐渐向DICOM标准靠拢&#xff0c;因此&#xff0c;我们在进行医学图像处理的过程中&#xff0c;经常需要自己编写和DICOM格式的图…

对象与函数

摘自《UMLOOPC嵌入式C语言开发精讲》 11.3 对象与函数11.3.1 函数的角色经济诺贝尔奖得主H.A.Simon&#xff08;H.A.Simon&#xff0c;计算机人工智能之父&#xff09;在其1962年的文章《The Architecture of Complexity》中说道&#xff1a;“从小系统建造成庞大系统时&…

android打包工具多渠道批量打包,Android 快速渠道批量打包详解教程-美团多渠道打包方案...

今天写一篇文章来总结下android批量打渠道包美团版本。之前项目上一直用的是gradle 批量打包方式&#xff0c;那个速度啊真是令人发指&#xff0c;15个渠道得跑上半个小时&#xff0c;出去吃顿饭回来&#xff0c;还在跑。特别是赶上项目上线的话&#xff0c;如果给测试提交了正…