设计模式-对象创建

反转基因福娃  金牌会员 | 昨天 05:32 | 来自手机 | 显示全部楼层 | 阅读模式
打印 上一主题 下一主题

主题 953|帖子 953|积分 2859

前言

“对象创建”模式:
通过“对象创建” 模式绕开new,来制止对象创建(new)过程中所导致的紧耦合(依赖具体类),从而支持对象创建的稳定。它是接口抽象之后的第一步工作。
典型模式:


  • Factory Method 工厂方法
  • Abstract Factory 抽象工厂
  • Prototype
  • Builder
1. Factory Method

1.1 模式介绍

动机:在软件系统中,经常面临着创建对象的工作;由于需求的变化,需要创建的对象的具体类型经常变化。
如何应对这种变化?如何绕过常规的对象创建方法(new),提供一种“封装机制”来制止客户程序和这种“具体对象创建工作”的紧耦合?
   界说一个用于创建对象的接口,让子类决定实例化哪一个类。Factory Method使得一个类的实例化延迟(目的:解耦,手段:虚函数)到子类。
  
——《设计模式》GoF

  1.2 模式代码

1.2.1 问题代码

  1. class ISplitter{
  2.     public:
  3.         virtual void split()=0;
  4.         virtual ~ISplitter(){}
  5.     };
  6.    
  7.     class BinarySplitter : public ISplitter{
  8.         
  9.     };
  10.    
  11.     class TxtSplitter: public ISplitter{
  12.         
  13.     };
  14.    
  15.     class PictureSplitter: public ISplitter{
  16.         
  17.     };
  18.    
  19.     class VideoSplitter: public ISplitter{
  20.         
  21.     };
  22.    
  23.    
  24. class MainForm : public Form
  25. {
  26.         TextBox* txtFilePath;
  27.         TextBox* txtFileNumber;
  28.         ProgressBar* progressBar;
  29. public:
  30.         void Button1_Click(){
  31.         
  32.                 ISplitter * splitter=
  33.             new BinarySplitter();//依赖具体类
  34.         
  35.         splitter->split();
  36.         }
  37. };
复制代码
你有一个按钮,点击按钮以后可以对二进制文件、文本文件、图片文件、视频文件举行分割,如果按照上述代码举行编写,其依赖具体类,如果你想增加其他文件格式方法时,得修改button里的方法,这会使得封装性被粉碎
1.2.2 重构代码

  1. //抽象类
  2. class ISplitter{
  3.     public:
  4.         virtual void split()=0;
  5.         virtual ~ISplitter(){}
  6.     };
  7.    
  8.    
  9. //工厂基类
  10. class SplitterFactory{
  11. public:
  12.     virtual ISplitter* CreateSplitter()=0;
  13.     virtual ~SplitterFactory(){}
  14. };
  15. //具体类
  16. class BinarySplitter : public ISplitter{
  17.     virtual void split()
  18.     {}
  19. };
  20. class TxtSplitter: public ISplitter{
  21.     virtual void split()
  22.     {}
  23. };
  24. class PictureSplitter: public ISplitter{
  25.     virtual void split()
  26.     {}
  27. };
  28. class VideoSplitter: public ISplitter{
  29.     virtual void split()
  30.     {}
  31. };
  32. //具体工厂
  33. class BinarySplitterFactory: public SplitterFactory{
  34. public:
  35.     virtual ISplitter* CreateSplitter(){
  36.         return new BinarySplitter();
  37.     }
  38. };
  39. class TxtSplitterFactory: public SplitterFactory{
  40. public:
  41.     virtual ISplitter* CreateSplitter(){
  42.         return new TxtSplitter();
  43.     }
  44. };
  45. class PictureSplitterFactory: public SplitterFactory{
  46. public:
  47.     virtual ISplitter* CreateSplitter(){
  48.         return new PictureSplitter();
  49.     }
  50. };
  51. class VideoSplitterFactory: public SplitterFactory{
  52. public:
  53.     virtual ISplitter* CreateSplitter(){
  54.         return new VideoSplitter();
  55.     }
  56. };
  57. class MainForm : public Form
  58. {
  59.     SplitterFactory*  factory;//工厂
  60. public:
  61.    
  62.     MainForm(SplitterFactory*  factory){
  63.         this->factory=factory;
  64.     }
  65.    
  66.         void Button1_Click(){
  67.         
  68.                 ISplitter * splitter=
  69.             factory->CreateSplitter(); //多态new
  70.         
  71.         splitter->split();
  72.         }
  73. };
复制代码
解决方法:设计一个工厂基类,声明一个创建对象的接口,对象底子工厂基类,实现创建对象的方法,即可实现运行时绑定
1.3 模式类图


1.4 要点总结



  • Factory Method模式用于隔离类对象的使用者和具体类型之间的耦合关系。面对一个经常变化的具体类型,紧耦合关系(new)会导致软件的脆弱。
  • Factory Method模式通过面向对象的本领,将所要创建的具体对象工作延迟到子类,从而实现一种扩展(而非更改)的策略,较好地解决了这种紧耦合关系。
  • Factory Method模式解决“单个对象”的需求变化。缺点在于要求创建方法/参数相同。
2. Abstract Factory

2.1 模式介绍

动机:在软件系统中,经常面临着“一系列相互依赖的对象”的创建工作;同时,由于需求的变化,每每存在更多系列对象的创建工作。
如何应对这种变化?如何绕过常规的对象创建方法(new),提供一种“封装机制”来制止客户程序和这种“多系列具体对象创建工作”的紧耦合?
   提供一个接口,让该接口负责创建一系列“相关或者相互依赖的对象”,无需指定它们具体的类。
  
——《设计模式》GoF

  2.2 模式代码

抽象工厂是工厂方法模式的子集,当要创建的对象之间有关联时才使用抽象工厂
2.2.1 问题代码

假设现在要实现SQL处理的功能
问题代码1:直接将类型硬编码到功能里,如果有多种数据库,比如MySQL、Oracle等等,就会不利于扩展
  1. class EmployeeDAO{
  2.    
  3. public:
  4.     vector<EmployeeDO> GetEmployees(){
  5.         SqlConnection* connection =
  6.             new SqlConnection();
  7.         connection->ConnectionString = "...";
  8.         SqlCommand* command =
  9.             new SqlCommand();
  10.         command->CommandText="...";
  11.         command->SetConnection(connection);
  12.         SqlDataReader* reader = command->ExecuteReader();
  13.         while (reader->Read()){
  14.         }
  15.     }
  16. };
复制代码
问题代码2:在问题代码1的底子上,使用工厂方法解决依赖具体类问题
  1. //数据库访问有关的基类
  2. class IDBConnection{
  3.    
  4. };
  5. class IDBConnectionFactory{
  6. public:
  7.     virtual IDBConnection* CreateDBConnection()=0;
  8. };
  9. class IDBCommand{
  10.    
  11. };
  12. class IDBCommandFactory{
  13. public:
  14.     virtual IDBCommand* CreateDBCommand()=0;
  15. };
  16. class IDataReader{
  17.    
  18. };
  19. class IDataReaderFactory{
  20. public:
  21.     virtual IDataReader* CreateDataReader()=0;
  22. };
  23. //支持SQL Server
  24. class SqlConnection: public IDBConnection{
  25.    
  26. };
  27. class SqlConnectionFactory:public IDBConnectionFactory{
  28.    
  29. };
  30. class SqlCommand: public IDBCommand{
  31.    
  32. };
  33. class SqlCommandFactory:public IDBCommandFactory{
  34.    
  35. };
  36. class SqlDataReader: public IDataReader{
  37.    
  38. };
  39. class SqlDataReaderFactory:public IDataReaderFactory{
  40.    
  41. };
  42. //支持Oracle
  43. class OracleConnection: public IDBConnection{
  44.    
  45. };
  46. class OracleCommand: public IDBCommand{
  47.    
  48. };
  49. class OracleDataReader: public IDataReader{
  50.    
  51. };
  52. class EmployeeDAO{
  53.     IDBConnectionFactory* dbConnectionFactory;
  54.     IDBCommandFactory* dbCommandFactory;
  55.     IDataReaderFactory* dataReaderFactory;
  56.    
  57.    
  58. public:
  59.     vector<EmployeeDO> GetEmployees(){
  60.         IDBConnection* connection =
  61.             dbConnectionFactory->CreateDBConnection();
  62.         connection->ConnectionString("...");
  63.         IDBCommand* command =
  64.             dbCommandFactory->CreateDBCommand();
  65.         command->CommandText("...");
  66.         command->SetConnection(connection); //关联性
  67.         IDBDataReader* reader = command->ExecuteReader(); //关联性
  68.         while (reader->Read()){
  69.         }
  70.     }
  71. };
复制代码
如果转达的dbConnectionFactory、dbCommandFactory、dataReaderFactory不是同一系列的就会出问题,比方一部分是MySQL对象,一部分是Oracle对象
2.2.2 重构代码

  1. //数据库访问有关的基类
  2. class IDBConnection{
  3.    
  4. };
  5. class IDBCommand{
  6.    
  7. };
  8. class IDataReader{
  9.    
  10. };
  11. class IDBFactory{
  12. public:
  13.     virtual IDBConnection* CreateDBConnection()=0;
  14.     virtual IDBCommand* CreateDBCommand()=0;
  15.     virtual IDataReader* CreateDataReader()=0;
  16.    
  17. };
  18. //支持SQL Server
  19. class SqlConnection: public IDBConnection{
  20.    
  21. };
  22. class SqlCommand: public IDBCommand{
  23.    
  24. };
  25. class SqlDataReader: public IDataReader{
  26.    
  27. };
  28. class SqlDBFactory:public IDBFactory{
  29. public:
  30.     virtual IDBConnection* CreateDBConnection()=0;
  31.     virtual IDBCommand* CreateDBCommand()=0;
  32.     virtual IDataReader* CreateDataReader()=0;
  33. };
  34. //支持Oracle
  35. class OracleConnection: public IDBConnection{
  36.    
  37. };
  38. class OracleCommand: public IDBCommand{
  39.    
  40. };
  41. class OracleDataReader: public IDataReader{
  42.    
  43. };
  44. class EmployeeDAO{
  45.     IDBFactory* dbFactory;
  46.    
  47. public:
  48.     vector<EmployeeDO> GetEmployees(){
  49.         IDBConnection* connection =
  50.             dbFactory->CreateDBConnection();
  51.         connection->ConnectionString("...");
  52.         IDBCommand* command =
  53.             dbFactory->CreateDBCommand();
  54.         command->CommandText("...");
  55.         command->SetConnection(connection); //关联性
  56.         IDBDataReader* reader = command->ExecuteReader(); //关联性
  57.         while (reader->Read()){
  58.         }
  59.     }
  60. };
复制代码
将一系列方法封装在一起,这便是抽象工厂模式
2.3 模式类图


2.4 要点总结



  • 如果没有应对“多系列对象构建”的需求变化,则没有必要使用Abstract Factory模式,这时候使用简朴的工厂完全可以。
  • “系列对象”指的是在某一特定系列下的对象之间有相互依赖、或作用的关系。不同系列的对象之间不能相互依赖。
  • Abstract Factory模式重要在于应对“新系列”的需求变动。其缺点在于难以应对“新对象”的需求变动。
3. Prototype

3.1 模式介绍

原型是一种创建型设计模式,它允许您复制现有对象,而不使您的代码依赖于它们的类。
问题:
假设你有一个对象,你想创建它的一个精确副本。你会怎么做?首先,你必须创建一个相同类的新对象。然后你必须遍历原始对象的所有字段并将其值复制到新对象。
很好!但是有一个问题。并非所有对象都可以通过这种方式复制,由于某些对象的字段可能是私有的,从对象自己外部不可见。

直接方法还有一个问题。由于您必须知道对象的类才能创建副本,因此您的代码将依赖于该类。如果额外的依赖关系不吓到您,那么还有另一个问题。偶然您只知道对象遵循的接口,但不知道其具体类,比方,当方法中的参数接受遵循某个接口的任何对象时。
3.2 模式代码

  1. //抽象类
  2. class ISplitter{
  3. public:
  4.     virtual void split()=0;
  5.     virtual ISplitter* clone()=0; //通过克隆自己来创建对象
  6.    
  7.     virtual ~ISplitter(){}
  8. };
  9.    
  10.    
  11.    
  12.    
  13. //具体类
  14. class BinarySplitter : public ISplitter{
  15. public:
  16.     virtual ISplitter* clone(){
  17.         return new BinarySplitter(*this);
  18.     }
  19.     virtual void split()
  20.     {}
  21. };
  22.    
  23. class TxtSplitter: public ISplitter{
  24. public:
  25.     virtual ISplitter* clone(){
  26.         return new TxtSplitter(*this);
  27.     }
  28.     virtual void split()
  29.     {}
  30. };
  31. class PictureSplitter: public ISplitter{
  32. public:
  33.     virtual ISplitter* clone(){
  34.         return new PictureSplitter(*this);
  35.     }
  36.     virtual void split()
  37.     {}
  38. };
  39. class VideoSplitter: public ISplitter{
  40. public:
  41.     virtual ISplitter* clone(){
  42.         return new VideoSplitter(*this);
  43.     }
  44.     virtual void split()
  45.     {}
  46. };
  47.    
  48.    
  49. class MainForm : public Form
  50. {
  51.     ISplitter*  prototype;//原型对象
  52. public:
  53.    
  54.     MainForm(ISplitter*  prototype){
  55.         this->prototype=prototype;
  56.     }
  57.    
  58.         void Button1_Click(){
  59.                 ISplitter * splitter=
  60.             prototype->clone(); //克隆原型
  61.         
  62.         splitter->split();
  63.         }
  64. };
复制代码
3.3 模式类图


3.4 要点总结



  • 您可以克隆对象而不与其具体类耦合。
  • 您可以摆脱重复的初始化代码,转而克隆预先构建的原型。
  • 您可以更加方便地制作复杂的物体。
  • 处理复杂对象的设置预设时,您可以得到继承的替换方法。
4. Builder

4.1 模式介绍

动机:在软件系统中,偶然候面临着“一个复杂对象”的创建工作,其通常由各个部分的子对象用一定的算法构成;由于需求的变化,这个复杂对象的各个部分经常面临着剧烈的变化,但是将它们组合在一起的算法却相对稳定。
如何应对这种变化?如何提供一种“封装机制”来隔离出“复杂对象的各个部分”的变化,从而保持系统中的“稳定构建算法”不随着需求改变而改变?
   将一个复杂对象的构建与其表示相分离,使得同样的构建过程(稳定)可以创建不同的表示(变化)。
  
——《设计模式》GoF

  4.2 模式代码

  1. class House{
  2.     //....
  3. };
  4. class HouseBuilder {
  5. public:
  6.     House* GetResult(){
  7.         return pHouse;
  8.     }
  9.     virtual ~HouseBuilder(){}
  10. protected:
  11.    
  12.     House* pHouse;
  13.         virtual void BuildPart1()=0;
  14.     virtual void BuildPart2()=0;
  15.     virtual void BuildPart3()=0;
  16.     virtual void BuildPart4()=0;
  17.     virtual void BuildPart5()=0;
  18.        
  19. };
  20. class StoneHouse: public House{
  21.    
  22. };
  23. class StoneHouseBuilder: public HouseBuilder{
  24. protected:
  25.    
  26.     virtual void BuildPart1(){
  27.         //pHouse->Part1 = ...;
  28.     }
  29.     virtual void BuildPart2(){
  30.         
  31.     }
  32.     virtual void BuildPart3(){
  33.         
  34.     }
  35.     virtual void BuildPart4(){
  36.         
  37.     }
  38.     virtual void BuildPart5(){
  39.         
  40.     }
  41.    
  42. };
  43. class HouseDirector{
  44.    
  45. public:
  46.     HouseBuilder* pHouseBuilder;
  47.    
  48.     HouseDirector(HouseBuilder* pHouseBuilder){
  49.         this->pHouseBuilder=pHouseBuilder;
  50.     }
  51.    
  52.     House* Construct(){
  53.         
  54.         pHouseBuilder->BuildPart1();
  55.         
  56.         for (int i = 0; i < 4; i++){
  57.             pHouseBuilder->BuildPart2();
  58.         }
  59.         
  60.         bool flag=pHouseBuilder->BuildPart3();
  61.         
  62.         if(flag){
  63.             pHouseBuilder->BuildPart4();
  64.         }
  65.         
  66.         pHouseBuilder->BuildPart5();
  67.         
  68.         return pHouseBuilder->GetResult();
  69.     }
  70. };
复制代码
构建器HouseBuilder负责界说构建House时每个步调的具体接口(变化)和管理正在构建的对象,由子类继承并实现接口;
HouseDirector负责实现House在构建时的整体流程(不变)
4.3 模式类图


4.4 要点总结



  • Builder 模式重要用于“分步调构建一个复杂的对象”。在这其中“分步调”是一个稳定的算法,而复杂对象的各个部分则经常变化。
  • 变化点在哪里,封装哪里—— Builder模式重要在于应对“复杂对象各个部分”的频繁需求变动。其缺点在于难以应对“分步调构建算法”的需求变动。
  • 在Builder模式中,要注意不同语言中构造器内调用虚函数的差异(C++ vs. C#) 。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

反转基因福娃

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表