C++设计模式之1-工厂模式

简介:

(一)工厂模式描述

定义:为创建一组相关或相互依赖的对象提供一个接口,而且无需指定他们的具体类。

类型:创建类模式

用途:工厂模式主要是为创建对象提供过渡接口,以便将创建对象的具体过程屏蔽隔离起来,降低耦合度

    达到提高灵活性的目的。

类图:



现在一般看来将工厂模式分为三类:

1)简单工厂模式(Simple Factory

2)工厂方法模式(Factory Method

3)抽象工厂模式(Abstract Factory

这三种模式从上到下逐步抽象,并且更具一般性。

GOF在《设计模式》一书中将工厂模式分为两类:

工厂方法模式(Factory Method)与抽象工厂模式(Abstract Factory)。

将简单工厂模式(Simple Factory)看为工厂方法模式的一种特例,两者归为一类。

但是两种看法本质上是一致的,而且我们没必要深究那么多,下面来看看这些工厂模式是怎么来“治病”的。

工厂模式属于创建型模式,大致可以分为三类,简单工厂模式、工厂方法模式、抽象工厂模式。听上去差不多,都是工厂模式。

下面一个个介绍,首先介绍简单工厂模式,它的主要特点是需要在工厂类中做判断,从而创造相应的产品。当增加新的产品时,就需要修改工厂类。有点抽象,

举个例子就明白了。有一家生产处理器核的厂家,它只有一个工厂,能够生产两种型号AB的处理器核。不同的客户有不同的需求,有的客户喜欢A核,有的客户偏爱B核,怎么满足这种需求呢,

简单工厂,客户需要什么样的处理器核,一定要显示地告诉生产工厂。下面给出一种实现方案。

(二)简单工厂模式

简单工厂模式又称静态工厂方法模式。命名上就可以看出这个模式一定很简单。它存在的目的很简单:定义一个用于创建对象的接口

先来看看它的组成

① 工厂类角色:这是本模式的核心,含有一定的商业逻辑和判断逻辑。它往往由一个具体类实现。

② 抽象产品角色:它一般是具体产品继承的父类或者实现的接口。由接口或者抽象类来实现。

③ 具体产品角色:工厂类所创建的对象就是此角色的实例。由一个具体类实现

  1. #include <iostream>  
  2.   
  3. // 生成产品依据标识   
  4. typedef enum ClassType  
  5. {  
  6.     SINGCORE_A,  
  7.     SINGCORE_B,   
  8. }ClassType;  
  9.   
  10.   
  11. ////////////////////////////////////////////////////////////////////////////////  
  12. // 基础产品类 -=> 对应于抽象产品角色  
  13. class SingCore  
  14. {  
  15. public :  
  16.     virtual ~SingCore( ){ };        // 虚析构函数   
  17.       
  18.     virtual void Show( ) = 0;       // 产品的显示函数   
  19. };  
  20.   
  21. // 单核产品S -=> 对应于具体产品角色  
  22. class SingCoreA : public SingCore  
  23. {  
  24. public :  
  25.     virtual ~SingCoreA( ){ };       // 虚析构函数   
  26.       
  27.     void Show( )  
  28.     {  
  29.         std::cout <<"SingCore A..." <<std::endl;   
  30.     }   
  31. };    
  32.   
  33.   
  34. // 单核产品B -=> 对应于具体产品角色  
  35. class SingCoreB : public SingCore  
  36. {  
  37. public :  
  38.     virtual ~SingCoreB( ){ };       // 虚析构函数   
  39.       
  40.     void Show( )  
  41.     {  
  42.         std::cout <<"SingCore B..." <<std::endl;   
  43.     }     
  44. };   
  45. ////////////////////////////////////////////////////////////////////////////////  
  46. //  
  47. //  
  48. //  
  49. ////////////////////////////////////////////////////////////////////////////////  
  50. // 工厂类 -=> 对应于工厂角色  
  51. class Factory  
  52. {  
  53. public :  
  54.     virtual ~Factory( ){ };             // 虚析构函数   
  55.   
  56.     SingCore* CreateSingCore(ClassType classType)  
  57.     {   
  58.         switch(classType)  
  59.         {  
  60.             case SINGCORE_A :  
  61.             {  
  62.                 return new SingCoreA( );   
  63.             }  
  64.               
  65.             case SINGCORE_B :  
  66.             {  
  67.                 return new SingCoreB( );  
  68.             }  
  69.         }  
  70.     }   
  71. };  
  72. ////////////////////////////////////////////////////////////////////////////////  
  73. //  
  74. //  
  75. //  
  76. ////////////////////////////////////////////////////////////////////////////////  
  77.   
  78.   
  79. int main()  
  80. {  
  81.       
  82.     Factory *factory = new Factory( );  
  83.       
  84.     factory->CreateSingCore(SINGCORE_A)->Show( );   
  85.     factory->CreateSingCore(SINGCORE_B)->Show( );  
  86.           
  87.     delete factory;   
  88. }  

 首先,使用了简单工厂模式后,我们的程序更加符合现实中的情况;而且客户端免除了直接创建产品对象的责任,而仅仅负责消费产品,使客户端不再依赖与具体产品的创建,就像我们买产品A和产品B,我们只关心它是不是我们需要的产品,并不关心它是怎么被创建的。

但是这样设计的也有缺点,就是要增加新的核类型时,就需要修改工厂类。这就违反了开放封闭原则:软件实体(类、模块、函数)可以扩展,但是不可修改。可想而知对于新产品的加入,工厂类是很被动的。对于这样的工厂类,我们称它为全能类或者上帝类。
       
我们举的例子是最简单的情况,而在实际应用中,很可能产品是一个多层次的树状结构。由于简单工厂模式中只有一个工厂类来对应这些产品,所以这可能会把我们的上帝累坏了,也累坏了我们这些程序员
于是工厂方法模式作为救世主出现了。


三 工厂方法模式

所谓工厂方法模式,是指定义一个用于创建对象的接口,让子类决定实例化哪一个类。

Factory Method工厂方法模式使一个类的实例化延迟到其子类。

工厂方法模式去掉了简单工厂模式中工厂方法的静态属性,使得它可以被子类继承。

这样在简单工厂模式里集中在工厂方法上的压力可以由工厂方法模式里不同的工厂子类来分担。

你应该大致猜出了工厂方法模式的结构,来看下它的组成:

① 抽象工厂角色: 这是工厂方法模式的核心,它与应用程序无关。是具体工厂角色必须实现的接口或者必须继承的父类。它由抽象类或者接口来实现。

 具体工厂角色:它含有和具体业务逻辑有关的代码。由应用程序调用以创建对应的具体产品的对象。

③ 抽象产品角色:它是具体产品继承的父类或者是实现的接口。一般有抽象类或者接口来实现。

④具体产品角色:具体工厂角色所创建的对象就是此角色的实例。由具体的类来实现。

还是以刚才的例子解释。这家生产处理器核的产家赚了不少钱,于是决定再开设一个工厂专门用来生产B型号的单核,而原来的工厂专门用来生产A型号的单核。这时,客户要做的是找好工厂,比如要A型号的核,就找A工厂要;否则找B工厂要,不再需要告诉工厂具体要什么型号的处理器核了。

  1. #include <iostream>  
  2.   
  3. ////////////////////////////////////////////////////////////////////////////////   
  4. // 核心产品基类  -=> 对应于抽象产品角色  
  5. class SingCore  
  6. {  
  7. public :  
  8.     virtual ~SingCore( ){ };        // 虚析构函数  
  9.        
  10.     virtual void Show( ) = 0;       // 产品显示函数   
  11. };   
  12.   
  13.   
  14. // 核心产品A  -=> 对应于具体产品角色  
  15. class SingCoreA : public SingCore   
  16. {  
  17. public :  
  18.     virtual ~SingCoreA( ){ };       // 虚析构函数  
  19.        
  20.     void Show( )        // 产品显示函数   
  21.     {  
  22.         std::cout <<"SingCore A..." <<std::endl;   
  23.     }  
  24. };  
  25.   
  26. // 核心产品B  -=> 对应于具体产品角色  
  27. class SingCoreB : public SingCore  
  28. {  
  29. public :  
  30.     virtual ~SingCoreB( ){ };       // 虚析构函数   
  31.       
  32.     void Show( )            // 产品显示函数   
  33.     {  
  34.         std::cout <<"SingCore B..." <<std::endl;  
  35.     }   
  36. };  
  37. ////////////////////////////////////////////////////////////////////////////////  
  38. //   
  39. //  
  40. //  
  41. //   
  42. ////////////////////////////////////////////////////////////////////////////////  
  43. // 工厂的基类 -=> 对应于抽象工厂角色  
  44. class Factory  
  45. {  
  46. public:  
  47.     virtual ~Factory( ){ };         // 虚析构函数   
  48.       
  49.     virtual SingCore* CreateSingCore( ) = 0;    // 生产产品的生产线  
  50.        
  51. };  
  52.   
  53. // 生产核心A的工厂 -=> 对应于具体产品角色  
  54. class FactoryA : public Factory  
  55. {  
  56. public :  
  57.     virtual ~FactoryA( ){ };            // 虚析构函数   
  58.       
  59.     SingCoreA* CreateSingCore( )  
  60.     {  
  61.         return new SingCoreA( );  
  62.     }  
  63. };  
  64.   
  65.   
  66. // 生产核心B的工厂 -=> 对应于具体产品角色  
  67. class FactoryB : public Factory  
  68. {  
  69. public :   
  70.     virtual ~FactoryB( ){ };            // 虚析构函数   
  71.       
  72.     SingCoreB* CreateSingCore( )  
  73.     {  
  74.         return new SingCoreB( );  
  75.     }  
  76. };  
  77.   
  78. int main( )  
  79. {  
  80.     Factory *factoryA = new FactoryA( );  
  81.     factoryA->CreateSingCore( )->Show( );  
  82.       
  83.     Factory *factoryB = new FactoryB( );  
  84.     factoryB->CreateSingCore( )->Show( );  
  85.   
  86.     return 0;       
  87. }  
工厂方法模式使用继承自抽象工厂角色的多个子类来代替简单工厂模式中的“上帝类”。正如上面所说,这样便分担了对象承受的压力;而且这样使得结构变得灵活起来——当有新的产品产生时,只要按照抽象产品角色、抽象工厂角色提供的合同来生成,那么就可以被客户使用,而不必去修改任何已有的代码。可以看出工厂角色的结构也是符合开闭原则的!就相当于市面上同样的产品有很多个牌子,有A牌子和B牌子,每家都有一个单独的工厂用来生产。这样每次增加一个新的牌子的产品上市,都会有一家新的工厂出现。

五 抽象工厂模式

       好了那到底什么是抽象工工厂呢,它到底有什么作用呢?

在将抽象工厂前我们先来认识一下产品族。

还是举这个例子,这家公司的技术不断进步,不仅可以生产单核处理器,也能生产多核处理器。每个处理器下都有AB两种型号的。那么这里A单核和B单核就同属于一个单核产品族。A多核和B多核就同属于一个多核产品族。

对于这种情况,就需要用到抽象工厂了。它的定义为提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。具体这样应用,这家公司还是开设两个工厂,一个专门用来生产A型号的单核多核处理器,而另一个工厂专门用来生产B型号的单核多核处理器,每个工厂用来生产一个产品族。

抽象工厂模式的用意为:给客户端提供一个接口,可以创建多个产品族中的产品对象

而且使用抽象工厂模式还要满足一下条件:

①系统中有多个产品族,而系统一次只可能消费其中一族产品。

同属于同一个产品族的产品以其使用。

看看抽象工厂模式的各个角色(和工厂方法的如出一辙):

①抽象工厂角色: 这是工厂方法模式的核心,它与应用程序无关。是具体工厂角色必须实现的接口或者必须继承的父类。它由抽象类或者接口来实现。

②具体工厂角色:它含有和具体业务逻辑有关的代码。由应用程序调用以创建对应的具体产品的对象。它由具体的类来实现。

③ 抽象产品角色:它是具体产品继承的父类或者是实现的接口。一般有抽象类或者接口来实现。

④具体产品角色:具体工厂角色所创建的对象就是此角色的实例。由具体的类来实现

抽象工厂模式和工厂方法模式的区别

可以说,抽象工厂模式和工厂方法模式的区别就在于需要创建对象的复杂程度上。

而且抽象工厂模式是三个里面最为抽象、最具一般性的。

你能见到的大部分抽象工厂模式都是这样的:它的里面是一堆工厂方法,每个工厂方法返回某种类型的对象。

如果说抽象工厂中的工厂是一个实际的工厂的话,那么工厂方法中的工厂更像现实中工厂的一条生产线

下面举个例子具体描述一下

①比如说工厂可以生产鼠标和键盘。那么抽象工厂的实现类(它的某个具体子类)的对象都可以生产鼠标和键盘,但可能工厂A生产的是罗技的键盘和鼠标,工厂B是微软的。这样A和B就是工厂,对应于抽象工厂;每个工厂生产的鼠标和键盘就是产品,对应于工厂方法;用了工厂方法模式,你替换生成键盘的工厂方法,就可以把键盘从罗技换到微软, 但是鼠标还是原来罗技的但是用了抽象工厂模式,你只要换家工厂,就可以同时替换鼠标和键盘一套。如果你要的产品有几十个,当然用抽象工厂模式一次替换全部最方便(这个工厂会替你用相应的工厂方法)所以说抽象工厂就像工厂,而工厂方法则像是工厂的一种产品生产线,

抽象工厂模式适合与如下的情况

    多个抽象产品类,每个抽象产品类可以派生出多个具体产品类。    一个抽象工厂类,可以派生出多个具体工厂类。    每个具体工厂类可以创建多个具体产品类的实例。

下面附上抽象工厂的代码

  1. #include <iostream>  
  2.   
  3. ////////////////////////////////////////////////////////////////////////////////  
  4. //单核产品类族  
  5. ////////////////////////////////////////////////////////////////////////////////  
  6. // 单核产品基类  
  7. class SingleCore    
  8. {    
  9. public:    
  10.     virtual void Show( ) const = 0;  
  11. };    
  12.   
  13. // 单核A    
  14. class SingleCoreA: public SingleCore    
  15. {    
  16. public:    
  17.     void Show( )const   
  18.     {   
  19.         std::cout<<"SingleCore A"<<std::endl;   
  20.     }    
  21. };    
  22.   
  23. // 单核B    
  24. class SingleCoreB: public SingleCore    
  25. {    
  26. public:    
  27.     void Show( ) const  
  28.     {   
  29.         std::cout<<"SingleCore B"<<std::endl;   
  30.     }    
  31. };    
  32.   
  33.   
  34.   
  35. ////////////////////////////////////////////////////////////////////////////////  
  36. // 多核产品类族  
  37. ////////////////////////////////////////////////////////////////////////////////  
  38. // 多核产品类族基类  
  39. class MultiCore        
  40. {      
  41. public:      
  42.     virtual void Show( ) const = 0;    
  43. };      
  44.   
  45. // 多核产品A  
  46. class MultiCoreA : public MultiCore        
  47. {      
  48. public:      
  49.     void Show() const  
  50.     {   
  51.         std::cout<<"Multi Core A"<<std::endl;  
  52.     }      
  53.       
  54. };      
  55.   
  56. // 多核产品B  
  57. class MultiCoreB : public MultiCore        
  58. {      
  59. public:      
  60.     void Show( ) const  
  61.     {  
  62.         std::cout<<"Multi Core B"<<std::endl;  
  63.     }      
  64. };      
  65.   
  66.   
  67. // 工厂      
  68. class Factory        
  69. {      
  70. public:      
  71.     virtual SingleCore* CreateSingleCore( ) = 0;    
  72.     virtual MultiCore* CreateMultiCore( ) = 0;    
  73. };      
  74.   
  75. // 工厂A,专门用来生产A型号的处理器      
  76. class FactoryA :public Factory      
  77. {      
  78. public:      
  79.     SingleCore* CreateSingleCore( )  
  80.     {   
  81.         return new SingleCoreA( );   
  82.     }      
  83.       
  84.     MultiCore* CreateMultiCore( )  
  85.     {  
  86.         return new MultiCoreA( );  
  87.     }      
  88. };      
  89.   
  90. // 工厂B,专门用来生产B型号的处理器      
  91. class FactoryB : public Factory      
  92. {      
  93. public:      
  94.     SingleCore* CreateSingleCore()  
  95.     {  
  96.         return new SingleCoreB( );  
  97.     }      
  98.       
  99.     MultiCore* CreateMultiCore( )  
  100.     {  
  101.         return new MultiCoreB( );  
  102.     }      
  103. };     
  104.   
  105.   
  106. int main()  
  107. {  
  108.     // 生产产品A系列的产品工厂   
  109.     FactoryA *factoryA = new FactoryA( );  
  110.     factoryA->CreateSingleCore( )->Show( );  
  111.     factoryA->CreateMultiCore( )->Show( );  
  112.   
  113.     // 生产B系列的产品工厂   
  114.     FactoryB *factoryB = new FactoryB( );  
  115.     factoryB->CreateSingleCore( )->Show( );  
  116.     factoryB->CreateMultiCore( )->Show( );  
  117. }  


本例采用C++设计,会造成内存泄漏,但是只是为了讲解一下工厂模式的基本思路,因此本例中不加以描述
但是在实际开发中我们可以采用在工厂类中添加生产产品链表,来避免内存泄漏。
关于 简单工厂模式,工厂方法模式和抽象工厂模式的异同 (2013-12-24 11:08)请参考博主转载的一篇博客
转载:http://blog.csdn.net/gatieme/article/details/17952033
目录
相关文章
|
5月前
|
设计模式 C++
C++一分钟之-设计模式:工厂模式与抽象工厂
【7月更文挑战第14天】设计模式是解决软件设计问题的通用方案。工厂模式与抽象工厂模式是创建型模式,用于对象创建而不暴露创建逻辑。工厂模式推迟实例化到子类,但过度使用会增加复杂性。抽象工厂则创建相关对象族,但过度抽象可能造成不必要的复杂度。两者均应按需使用,确保设计灵活性。代码示例展示了C++中如何实现这两种模式。
48 3
|
5月前
|
设计模式 安全 C++
C++一分钟之-C++中的设计模式:单例模式
【7月更文挑战第13天】单例模式确保类只有一个实例,提供全局访问。C++中的实现涉及线程安全和生命周期管理。基础实现使用静态成员,但在多线程环境下可能导致多个实例。为解决此问题,采用双重检查锁定和`std::mutex`保证安全。使用`std::unique_ptr`管理生命周期,防止析构异常和内存泄漏。理解和正确应用单例模式能提升软件的效率与可维护性。
67 2
|
7月前
|
设计模式 开发框架 算法
C++中的设计模式:基本概念与应用
C++中的设计模式:基本概念与应用
74 2
|
7月前
|
设计模式 算法 中间件
【C++ 可调用对象的应用】C++设计模式与现代编程技巧:深入可调用对象的世界
【C++ 可调用对象的应用】C++设计模式与现代编程技巧:深入可调用对象的世界
225 1
|
7月前
|
设计模式 算法 C++
从 C++ 优化状态机实现:结合设计模式的实用指南
从 C++ 优化状态机实现:结合设计模式的实用指南
579 1
|
7月前
|
设计模式 存储 Java
C++从入门到精通:3.5设计模式——提升代码可维护性与可扩展性的关键
C++从入门到精通:3.5设计模式——提升代码可维护性与可扩展性的关键
|
7月前
|
设计模式 机器学习/深度学习 算法
C++设计模式新篇章:掌握状态委托
C++设计模式新篇章:掌握状态委托
129 0
|
23天前
|
存储 编译器 C语言
【c++丨STL】string类的使用
本文介绍了C++中`string`类的基本概念及其主要接口。`string`类在C++标准库中扮演着重要角色,它提供了比C语言中字符串处理函数更丰富、安全和便捷的功能。文章详细讲解了`string`类的构造函数、赋值运算符、容量管理接口、元素访问及遍历方法、字符串修改操作、字符串运算接口、常量成员和非成员函数等内容。通过实例演示了如何使用这些接口进行字符串的创建、修改、查找和比较等操作,帮助读者更好地理解和掌握`string`类的应用。
37 2
|
29天前
|
存储 编译器 C++
【c++】类和对象(下)(取地址运算符重载、深究构造函数、类型转换、static修饰成员、友元、内部类、匿名对象)
本文介绍了C++中类和对象的高级特性,包括取地址运算符重载、构造函数的初始化列表、类型转换、static修饰成员、友元、内部类及匿名对象等内容。文章详细解释了每个概念的使用方法和注意事项,帮助读者深入了解C++面向对象编程的核心机制。
83 5
|
1月前
|
存储 编译器 C++
【c++】类和对象(中)(构造函数、析构函数、拷贝构造、赋值重载)
本文深入探讨了C++类的默认成员函数,包括构造函数、析构函数、拷贝构造函数和赋值重载。构造函数用于对象的初始化,析构函数用于对象销毁时的资源清理,拷贝构造函数用于对象的拷贝,赋值重载用于已存在对象的赋值。文章详细介绍了每个函数的特点、使用方法及注意事项,并提供了代码示例。这些默认成员函数确保了资源的正确管理和对象状态的维护。
79 4