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

2024-06-18 16:32

本文主要是介绍设计模式C++实现(4)——外观模式、组合模式,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!


软件领域中的设计模式为开发人员提供了一种使用专家设计经验的有效途径。设计模式中运用了面向对象编程语言的重要特性:封装、继承、多态,真正领悟设计模式的精髓是可能一个漫长的过程,需要大量实践经验的积累。最近看设计模式的书,对于每个模式,用C++写了个小例子,加深一下理解。主要参考《大话设计模式》和《设计模式:可复用面向对象软件的基础》(DP)两本书。本文介绍外观模式和组合模式的实现。

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


        相应的代码实现为:

[cpp]  view plain  copy
  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 plain  copy
  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 plain  copy
  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 plain  copy
  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/article/details/6667564










这篇关于设计模式C++实现(4)——外观模式、组合模式的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1072514

相关文章

关于C++中的虚拟继承的一些总结(虚拟继承,覆盖,派生,隐藏)

1.为什么要引入虚拟继承 虚拟继承是多重继承中特有的概念。虚拟基类是为解决多重继承而出现的。如:类D继承自类B1、B2,而类B1、B2都继承自类A,因此在类D中两次出现类A中的变量和函数。为了节省内存空间,可以将B1、B2对A的继承定义为虚拟继承,而A就成了虚拟基类。实现的代码如下: class A class B1:public virtual A; class B2:pu

C++对象布局及多态实现探索之内存布局(整理的很多链接)

本文通过观察对象的内存布局,跟踪函数调用的汇编代码。分析了C++对象内存的布局情况,虚函数的执行方式,以及虚继承,等等 文章链接:http://dev.yesky.com/254/2191254.shtml      论C/C++函数间动态内存的传递 (2005-07-30)   当你涉及到C/C++的核心编程的时候,你会无止境地与内存管理打交道。 文章链接:http://dev.yesky

C++的模板(八):子系统

平常所见的大部分模板代码,模板所传的参数类型,到了模板里面,或实例化为对象,或嵌入模板内部结构中,或在模板内又派生了子类。不管怎样,最终他们在模板内,直接或间接,都实例化成对象了。 但这不是唯一的用法。试想一下。如果在模板内限制调用参数类型的构造函数会发生什么?参数类的对象在模板内无法构造。他们只能从模板的成员函数传入。模板不保存这些对象或者只保存他们的指针。因为构造函数被分离,这些指针在模板外

C++工程编译链接错误汇总VisualStudio

目录 一些小的知识点 make工具 可以使用windows下的事件查看器崩溃的地方 dumpbin工具查看dll是32位还是64位的 _MSC_VER .cc 和.cpp 【VC++目录中的包含目录】 vs 【C/C++常规中的附加包含目录】——头文件所在目录如何怎么添加,添加了以后搜索头文件就会到这些个路径下搜索了 include<> 和 include"" WinMain 和

如何开启和关闭3GB模式

https://jingyan.baidu.com/article/4d58d5414dfc2f9dd4e9c082.html

C/C++的编译和链接过程

目录 从源文件生成可执行文件(书中第2章) 1.Preprocessing预处理——预处理器cpp 2.Compilation编译——编译器cll ps:vs中优化选项设置 3.Assembly汇编——汇编器as ps:vs中汇编输出文件设置 4.Linking链接——链接器ld 符号 模块,库 链接过程——链接器 链接过程 1.简单链接的例子 2.链接过程 3.地址和

C++必修:模版的入门到实践

✨✨ 欢迎大家来到贝蒂大讲堂✨✨ 🎈🎈养成好习惯,先赞后看哦~🎈🎈 所属专栏:C++学习 贝蒂的主页:Betty’s blog 1. 泛型编程 首先让我们来思考一个问题,如何实现一个交换函数? void swap(int& x, int& y){int tmp = x;x = y;y = tmp;} 相信大家很快就能写出上面这段代码,但是如果要求这个交换函数支持字符型

mysql索引四(组合索引)

单列索引,即一个索引只包含单个列,一个表可以有多个单列索引,但这不是组合索引;组合索引,即一个索引包含多个列。 因为有事,下面内容全部转自:https://www.cnblogs.com/farmer-cabbage/p/5793589.html 为了形象地对比单列索引和组合索引,为表添加多个字段:    CREATE TABLE mytable( ID INT NOT NULL, use

十五.各设计模式总结与对比

1.各设计模式总结与对比 1.1.课程目标 1、 简要分析GoF 23种设计模式和设计原则,做整体认知。 2、 剖析Spirng的编程思想,启发思维,为之后深入学习Spring做铺垫。 3、 了解各设计模式之间的关联,解决设计模式混淆的问题。 1.2.内容定位 1、 掌握设计模式的"道" ,而不只是"术" 2、 道可道非常道,滴水石穿非一日之功,做好长期修炼的准备。 3、 不要为了

十四、观察者模式与访问者模式详解

21.观察者模式 21.1.课程目标 1、 掌握观察者模式和访问者模式的应用场景。 2、 掌握观察者模式在具体业务场景中的应用。 3、 了解访问者模式的双分派。 4、 观察者模式和访问者模式的优、缺点。 21.2.内容定位 1、 有 Swing开发经验的人群更容易理解观察者模式。 2、 访问者模式被称为最复杂的设计模式。 21.3.观察者模式 观 察 者 模 式 ( Obser