现在的位置: 首页 > 综合 > 正文

【GOF设计模式之路】– Factory

2013年03月31日 ⁄ 综合 ⁄ 共 19658字 ⁄ 字号 评论关闭

出处:http://blog.csdn.net/masefee/article/details/6007011 

自从开始工作,就感觉精力相比在大学时有很大幅度的下降。大二那一年精力最旺盛,自从大二结束开始工作到现在,两年时间,似乎精力都已经不受自己控制了。如果对一些技术研究工作不是很感兴趣,下班之后基本上到晚上10点左右就想睡觉。工作两年加上大二的一年,一直到现在都坚持每天必须有新的东西进入脑子,进步倒是明显感受到了,但真担心现在的精力还能坚持几年的技术研究。但愿不要像大家说的到了30岁以后就不适合做技术研究了,我个人觉得人活着就是为了做自己喜欢的事,那么就等到自己不再喜欢技术研究时再考虑转型吧。这个过程可能是一辈子,也可能是短短的几年,因人而异吧,先走好当前的路!come
on!!

 

不知不觉距写前一篇Singleton时已经有一个多月了,一是忙,二是精力不足,三是加上烦心的事就完全没心情写博了。有时候一直在想人活着是为了啥,似乎没有明确的答案。可能我还需要磨练吧。前一篇Singleton,就有一些朋友说写得比较复杂,在实际中基本不会搞得那么复杂,我之前也说过,设计模式并不需要严格遵循,可以根据实际情况做一些具体特殊的优化和演化,所以复杂的情况是应付复杂的需要,简单的是为了简单的需要。我们也没有必要为了简单的需要而使用复杂的规则,反之亦然。也就是所谓的灵活应对吧,更何况本系列的设计模式的示例是用C++解释的。更好玩的是有朋友的评论Singleton:“这是我见到过写得最好的Singleton”,这让我倍感欣慰,可这时又有朋友回复这个朋友的评论说:“是写得最多才对!”。欣慰之下又多了一些反思,难到我写的Singleton真的没有被参考的价值?其实,反过来想,我写博并不是为了最好最牛,只是习惯性写写,对自己有帮助,做到自己的最好即可。当然既然写出来了,也尽量在能力范围内不误导别人,也非常乐意接受别人批评。批评对于我来说是一面很不错的镜子。

 

好了,回归正题,本篇介绍工厂模式(Factory),在本文中,会介绍三种工厂模式相关的设计,即:(简单工厂)Simple Factory、(工厂方法)Factory Method(抽象工厂)Abstract Factory。虽然Simple Factory不是GOF的成员,但它在实际中也很常见和实用,通常作为Factory的一种特殊模式。本系列是以GOF设计模式为标题,但并不表示所有的模式都得在GOF的范围内,也即所谓的灵活吧!

 

简单工厂(Simple Factory)

还是以最简单实用的简单工厂开始,也好逐步加深印象,同时便于理解。所谓简单工厂(Simple Factory),自然也就是简单设计为主,直截了当。举个例子,例如网络游戏,在游戏世界里有很多个对象(Object),例如玩家(Player)、NPC、怪物(Monster)等。这些对象就好比一个个的产品,它们属于一个产品大类。而这一个个的产品又是由某个工厂所制造出来的,这里的工厂就可以是对象管理器。我们用户在想要创建一个对象时,只需要告诉对象管理器(工厂)我们需要什么类型的对象(产品),然后就把创建(生产)对象(产品)的任务托付给了对象管理器(工厂)。而我们只需要使用创建(生产)出来的对象(产品),专注于其商业逻辑。

 

由此我们可以构建一个简单工厂,可以有两种形式,一是每一种对象都使用一个创建函数,二是所有对象都使用同一个创建函数,由参数区分创建的对象的种类。在实际中,往往偏向第二种形式。示例代码如下:

  1. //-----------------------------------------------------------------------------------
      
  2. //  Desc:   SimpleFactory Header File
      
  3. //  Author: masefee   
  4. //  Date:   2010.11   
  5. //  Copyright (C) 2010 masefee
      
  6. //-----------------------------------------------------------------------------------
      
  7. #ifndef __SIMPLEFACTORY_H__
      
  8. #define __SIMPLEFACTORY_H__   
  9. #include <cstdlib>
      
  10. const int IID_PLAYER  = 'PLY';  
  11. const int IID_NPC     = 'NPC';  
  12. const int IID_MONSTER = 'MON';  
  13. // Base Product   
  14. class IObject  
  15. {  
  16. public:  
  17.     IObject( void ) : m_iIID( 0 ){}  
  18.     virtual ~IObject( void ){}  
  19. public:  
  20.     IObject* DynamicCast( const int iIID ){ return ( iIID == m_iIID ) ? this : VCAST( iIID ); }  
  21.     virtual void OnRun( void ) = 0;  
  22. protected:  
  23.     virtual IObject* VCAST( const int iIID ){ return NULL; }  
  24. protected:  
  25.     int m_iIID;  
  26. };  
  27. // Product Player   
  28. class CPlayer : public IObject  
  29. {  
  30. public:  
  31.     CPlayer( void );  
  32.     ~CPlayer( void );  
  33. public:  
  34.     void OnRun( void );  
  35. protected:  
  36.     IObject* VCAST( const int iIID ){ return ( iIID == IID_PLAYER ) ? this : IObject::VCAST( iIID ); }  
  37. };  
  38. // Product NPC   
  39. class CNpc : public IObject  
  40. {  
  41. public:  
  42.     CNpc( void );  
  43.     ~CNpc( void );  
  44. public:  
  45.     void OnRun( void );  
  46. protected:  
  47.     IObject* VCAST( const int iIID ){ return ( iIID == IID_NPC ) ? this : IObject::VCAST( iIID ); }  
  48. };  
  49. // Product Monster   
  50. class CMonster : public IObject  
  51. {  
  52. public:  
  53.     CMonster( void );  
  54.     ~CMonster( void );  
  55. public:  
  56.     void OnRun( void );  
  57. protected:  
  58.     IObject* VCAST( const int iIID ){ return ( iIID == IID_MONSTER ) ? this : IObject::VCAST( iIID ); }  
  59. };  
  60. // Simple Factory   
  61. class CObjectManager  
  62. {  
  63. public:  
  64.     CObjectManager( void );  
  65.     ~CObjectManager( void );  
  66. public:  
  67.     IObject* CreateObject( const int iIID );  
  68. };  
  69. #endif  

  1. //-----------------------------------------------------------------------------------
      
  2. //  Desc:   SimpleFactory Source File
      
  3. //  Author: masefee   
  4. //  Date:   2010.11   
  5. //  Copyright (C) 2010 masefee
      
  6. //-----------------------------------------------------------------------------------
      
  7. #include <iostream>
      
  8. #include "SimpleFactory.h"   
  9. // Product Player   
  10. CPlayer::CPlayer( void )  
  11. {  
  12.     m_iIID = IID_PLAYER;  
  13. }  
  14. CPlayer::~CPlayer( void )  
  15. {  
  16.       
  17. }  
  18. void CPlayer::OnRun( void )  
  19. {  
  20.     std::cout << "Player Run" << std::endl;  
  21. }  
  22. // Product Npc   
  23. CNpc::CNpc( void )  
  24. {  
  25.     m_iIID = IID_NPC;  
  26. }  
  27. CNpc::~CNpc( void )  
  28. {  
  29. }  
  30. void CNpc::OnRun( void )  
  31. {  
  32.     std::cout << "NPC Run" << std::endl;  
  33. }  
  34. // Product Monster   
  35. CMonster::CMonster( void )  
  36. {  
  37.     m_iIID = IID_MONSTER;  
  38. }  
  39. CMonster::~CMonster( void )  
  40. {  
  41. }  
  42. void CMonster::OnRun( void )  
  43. {  
  44.     std::cout << "Monster Run" << std::endl;  
  45. }  
  46. // Simple Factory   
  47. CObjectManager::CObjectManager( void )  
  48. {  
  49. }  
  50. CObjectManager::~CObjectManager( void )  
  51. {  
  52. }  
  53. IObject* CObjectManager::CreateObject( const int iIID )  
  54. {  
  55.     switch( iIID )  
  56.     {  
  57.     case IID_PLAYER:  
  58.         return new CPlayer();  
  59.         break;  
  60.     case IID_NPC:  
  61.         return new CNpc();  
  62.         break;  
  63.     case IID_MONSTER:  
  64.         return new CMonster();  
  65.         break;  
  66.     default:  
  67.         return NULL;  
  68.         break;  
  69.     }  
  70. }  

调用如下:

  1. #include "SimpleFactory.h"
      
  2. int main( void )  
  3. {  
  4.     CObjectManager objMgr;  
  5.     IObject* pObj1 = objMgr.CreateObject( IID_PLAYER );  
  6.     IObject* pObj2 = objMgr.CreateObject( IID_MONSTER );  
  7.       
  8.     pObj1->OnRun();  
  9.     pObj2->OnRun();  
  10.     CPlayer* pPlayer = ( CPlayer* )pObj1->DynamicCast( IID_PLAYER );  
  11.     if ( pPlayer )  
  12.         pPlayer->OnRun();  
  13.     // cast return NULL
      
  14.     CMonster* pMonster = ( CMonster* )pObj1->DynamicCast( IID_MONSTER );  
  15.     if ( pMonster )  
  16.         pMonster->OnRun();  
  17.     delete pObj1;  
  18.     delete pObj2;  
  19.     system( "pause" );  
  20.     return 0;  
  21. }  

如上,IObject即是对象(产品)基类,所有对象(产品)都继承于它。CPlayer、CNpc和CMonster则是具体的对象(产品)类。CObjectManager则为对象管理器(简单工厂),它负责创建(生产)CPlayer、CNpc和CMonster等具体的对象(产品)。在上例中,我使用了IID这种形式来确定创建什么类的实体,IID可以理解为对象唯一ID。对象管理器在创建对象时可以根据唯一ID进行区分,如main函数中的pObj1和pObj2,另外,在很多场合都是使用的基类指针进行逻辑处理,在特定的时候会需要动态转换以确定这个IObject*是什么子类型(当然设计上不推荐这么做)。因此在IObject类里增加了DynamicCast函数,此函数可根据参数的IID值,返回具体的子类,如果没有找到则返回NULL。VCAST是一个虚函数,是为了向下定位查找子类是否有IID与其参数的IID相同,若没有则返回NULL(如上例中的DynamicCast(
IID_MONSTER )则会失败而返回NULL)。在上例中,IObject只被继承了一层,所以当nIID与子类的IID匹配时(如CPlayer对应IID_PLAYER),m_iIID == iIID始终是成立的,VCAST也就不会再调用,显得作用不大,但是当有多层继承时,而IObject类只能保存起子类继承关系中某一层的IID,此时,m_iIID == iIID就不一定成立了,此时VCAST的作用就明显了,例如CPlayer还有子类,则CPlayer的子类的VCAST应该设计为:

virtual IObject* VCAST( const int iIID ){ return ( iIID == IID_PLAYER || iIID == IID_SUBPLAYER ) ? this :
IObject::VCAST( iIID ); 

因为有多层继承关系时,可允许子类不重新修改IObject的m_iIID的值,所以判断了本身类的IID和基类的IID。当IID不等时,则直接调用IObject::VCAST( iIID )返回到IObject基类中,将由它统一决定返回值,本文中统一返回NULL。(VCAST函数的大部分逻辑都是一样的,可以考虑使用宏定义)

 

其实这个DynamicCast和VCAST组合也就起到了dynamic_cast的作用,dynamic_cast在效率上要低一些,它是通过RTTI描述符进行定位,而DynamicCast通过VCAST虚函数定位子类的VCAST。在编译时就已经决定了调用DynamicCast时该调用虚函数表里哪个虚函数,dynamic_cast的转换是具体存在的。(PS:在实际中并不推荐使用dynamic_cast和DynamicCast,在抽象一层应该做好接口,避免直接面对具体的对象类型)

 

如果对这个流程不清楚,可以自己写写再跟踪一下,就能有所体会了。

 

如果将对象的创建使用不同的创建函数,如上面所说的第一种形式,则CObjectManager可以设计为:

  1. class CObjectManager  
  2. {  
  3. public:  
  4.     CObjectManager( void );  
  5.     ~CObjectManager( void );  
  6. public:  
  7.     IObject* CreatePlayer( void );  
  8.     IObject* CreateNpc( void );  
  9.     IObject* CreateMonster( void );  
  10. };  

这样在使用时,就只能分开创建了,我个人偏好传递参数的方式进行创建。

 

Simple Factory有时有称作静态工厂,静态工厂也是简单工厂,与上面示例的不同之处在于工厂类的创建函数是静态的,以至于在创建对象时,可以不用创建工厂对象,如下:

  1. // 静态工厂   
  2. class CObjectManager  
  3. {  
  4. public:  
  5.     CObjectManager( void );  
  6.     ~CObjectManager( void );  
  7. public:  
  8.     static IObject* CreateObject( const int iIID );  
  9. };  
  10. // 调用   
  11. IObject* pObj1 = CObjectManager::CreateObject( IID_PLAYER );  
  12. IObject* pObj2 = CObjectManager::CreateObject( IID_MONSTER );  

这种方式在实际的复杂的继承情况中可能并不适用,它将创建函数设计为静态,便不能让其子类重写和扩展了。

上例的输出结果为:

Player Run
Monster Run
Player Run

最后一次DynamicCast( IID_MONSTER )失败了,返回NULL,不会输出。

 

为了更直观的总结一下简单工厂模式,如下图:

图1   简单工厂模式(Simple Factory)

好了,简单工厂也就差不多了,小结一下:

其优点:

一是将工厂中的各个产品的创建都集中到一起,便于管理与维护,能够减少以后修改的工作量。二是将主体逻辑与抽象逻辑分离,工厂负责抽象及创建出产品,用户则只需要负责主体逻辑,分工明确且非常协调。(这两点也可归结于整个工厂模式的好处)

其缺点:

对未来的扩展性适应不是非常良好,它对修改不封闭,即如果要新增加一个产品,则需要修改工厂的实现,这违反了开闭原则(OCP)。

 

工厂方法(Factory Method)

 

前面谈到Simple Factory的缺点时,发现它违反了开闭原则,每增加一个产品就得修改工厂创建函数的逻辑实现。例如要增加一个新的对象CItem(游戏中的道具),此时就得修改CreateObject函数,以后每增加一个对象都得这样做,CObjectManager就不能对修改封闭。

 

那么,如何才能解决这个问题呢,想想面向对象,想想多态,于是Factory Method模式应运而生。我们可以将工厂抽象了,然后再继承一系列的子工厂。例如某某集团公司,这个集团的名称可以只是挂一个名,而此集团下可以有很多个子公司,每个子公司就负责做具体的实事。而集团总部就只需要支配即可。每个子公司的人事、财政等运作都是独立的,互不干涉。假如要将集团战略发展到一个新的领域,只需要新建一个子公司或购买一个公司作为子公司。这也就是所谓的修改封闭。再例如某餐厅,最开始是只请了一个厨师(简单工厂),这个厨师只会做川菜,对于此刻餐厅的规模来说,已经完全足够了。随着这名厨师的厨艺被大家认可之后,餐厅的生意也越来越好了。需求也不断增加,更有外地的顾客光临,餐厅为了能够让外地的顾客能够尝到家乡的味道,于是“做出了一个艰难的决定”,要让厨师学习做异地菜肴,如鲁菜。可是厨师师傅又要下厨,又要学习,他都一把年纪了,哪儿有那么多精力呢,更何况这是一个熟能生巧的活。餐厅老板也能体会厨师师傅的苦,于是提升他为厨师总管(没办法,他资格最老嘛),然后又招聘了很多个厨师,有川菜厨师、鲁菜厨师、湘菜厨师等等。而厨师总管以后就不用下厨了,他只需要直接面对餐厅老板,下达命令。这样既形成培养模式,又能不让厨师总管学习做各种地域的菜肴了。需要新的地域菜肴就直接招聘新的厨师,而原来的厨师也不需要涉足太广。于是餐厅的规模也就越做越大了,老板成了亿万富翁。。。

 

了解了整体结构和流程之后,Factory Method和Simple Factory的区别其实不明显,唯一的区别只是将工厂抽象化了,然后再创建一系列的子工厂。CreateObject还是同样的逻辑,只是此刻的CreateObject不能为static了,它要被子工厂重写。还是先看代码吧,如下:

  1. // 增加了两个新的对象(产品)   
  2. const int IID_ITEM     = 'ITM';  
  3. const int IID_BUILDING = 'BLD';  
  4. // Product Item   
  5. class CItem : public IObject  
  6. {  
  7. public:  
  8.     CItem( void );  
  9.     ~CItem( void );  
  10. public:  
  11.     void OnRun( void );  
  12. protected:  
  13.     IObject* VCAST( const int iIID ){ return ( iIID == IID_ITEM ) ? this : IObject::VCAST( iIID ); }  
  14. };  
  15. // Product Building   
  16. class CBuilding : public IObject  
  17. {  
  18. public:  
  19.     CBuilding( void );  
  20.     ~CBuilding( void );  
  21. public:  
  22.     void OnRun( void );  
  23. protected:  
  24.     IObject* VCAST( const int iIID ){ return ( iIID == IID_BUILDING ) ? this : IObject::VCAST( iIID ); }  
  25. };  
  26.   
  27. // Product Item   
  28. CItem::CItem( void )  
  29. {  
  30.     m_iIID = IID_ITEM;  
  31. }  
  32.   
  33. CItem::~CItem( void )  
  34. {  
  35.   
  36. }  
  37.   
  38. void CItem::OnRun( void )  
  39. {  
  40.     std::cout << "Item Run" << std::endl;  
  41. }  
  42.   
  43. // Product Building   
  44. CBuilding::CBuilding( void )  
  45. {  
  46.     m_iIID = IID_BUILDING;  
  47. }  
  48.   
  49. CBuilding::~CBuilding( void )  
  50. {  
  51.   
  52. }  
  53.   
  54. void CBuilding::OnRun( void )  
  55. {  
  56.     std::cout << "Building Run" << std::endl;  
  57. }  

抽象工厂及子工厂:

  1. // Base Factory   
  2. class IObjectManager  
  3. {  
  4. public:  
  5.     IObjectManager( void ){}  
  6.     virtual ~IObjectManager( void ){}  
  7. public:  
  8.     virtual IObject* CreateObject( const int iIID ) = 0;  
  9. };  
  10. // Fight Object Factory   
  11. class CFightObjManager : public IObjectManager  
  12. {  
  13. public:  
  14.     CFightObjManager( void );  
  15.     ~CFightObjManager( void );  
  16. public:  
  17.     IObject* CreateObject( const int iIID );  
  18. };  
  19. // Region Object Factory
      
  20. class CRegionObjManager : public IObjectManager  
  21. {  
  22. public:  
  23.     CRegionObjManager( void );  
  24.     ~CRegionObjManager( void );  
  25. public:  
  26.     IObject* CreateObject( const int iIID );  
  27. };  

  1. // Fight Object Factory   
  2. CFightObjManager::CFightObjManager( void )  
  3. {  
  4. }  
  5. CFightObjManager::~CFightObjManager( void )  
  6. {  
  7. }  
  8. IObject* CFightObjManager::CreateObject( const int iIID )  
  9. {  
  10.     switch( iIID )  
  11.     {  
  12.     case IID_PLAYER:  
  13.         return new CPlayer();  
  14.         break;  
  15.     case IID_NPC:  
  16.         return new CNpc();  
  17.         break;  
  18.     case IID_MONSTER:  
  19.         return new CMonster();  
  20.         break;  
  21.     default:  
  22.         return NULL;  
  23.         break;  
  24.     }  
  25. }  
  26. // Region Object Manager   
  27. CRegionObjManager::CRegionObjManager( void )  
  28. {  
  29. }  
  30. CRegionObjManager::~CRegionObjManager( void )  
  31. {  
  32. }  
  33. IObject* CRegionObjManager::CreateObject( const int iIID )  
  34. {  
  35.     switch( iIID )  
  36.     {  
  37.     case IID_ITEM:  
  38.         return new CItem();  
  39.         break;  
  40.     case IID_BUILDING:  
  41.         return new CBuilding();  
  42.         break;  
  43.     default:  
  44.         return NULL;  
  45.         break;  
  46.     }  
  47. }  

 

用户:

  1. int main( void )  
  2. {  
  3.     IObjectManager* pFightObjMgr  = new CFightObjManager();  
  4.     IObjectManager* pRegionObjMgr = new CRegionObjManager();  
  5.     IObject* obj1 = pFightObjMgr->CreateObject( IID_NPC );  
  6.     IObject* obj2 = pRegionObjMgr->CreateObject( IID_BUILDING );  
  7.     obj1->OnRun();  
  8.     obj2->OnRun();  
  9.     delete obj1;  
  10.     delete obj2;  
  11.     delete pFightObjMgr;  
  12.     delete pRegionObjMgr;  
  13.     system( "pause" );  
  14.     return 0;  
  15. }  

如上,我们将原先的CObjectManager提升(抽象)为集团公司(抽象工厂):IObjectManager。而CPlayer、CNpc和CMonster还是作为同一个对象管理器(工厂)的对象(产品),由CFightObjManger(可战斗对象管理器)管理和创建(生产)。新增加的两个对象(产品):CItem(道具)和CBuilding(建筑物)则由新的CRegionObjManager(场景对象管理器)管理和创建(生产)。以后再增加新的对象则不需要改变CFightObjManger和CRegionObjManager管理器(工厂)。实现了修改封闭,符合OCP。此时,你可能发现有一个问题,CFightObjManger和CRegionObjManager明显是两大类,意思就是如果将CItem和CBuilding放到CFightObjManager里并不合适,反过来将CPlayer、CNpc和CMonster放到CRegionObjManager里创建也不怎么合适。这样就又可能出现违反OCP的情况,即如果CFightObjManger和CRegionObjManager已经存在,而新增的对象(产品)在类型上是应该属于它们两者中某一个工厂的,此刻创建新的管理器(工厂)就显得没必要。此时就还是得修改CFightObjManger或CRegionObjManager的实现。因此,要尽量解决这个问题,就得在设计工厂时,尽量把以后需要的产品都想到最全面,减少修改的次数,尽量实现修改封闭(PS:所以架构师也不是那么好做的-.-)。你总不可能在实际研发中把各个工厂都命名为Factory1,Factory2...哟!-_-!!!

 

这样看来,具体的工厂子类要尽量不被修改就得看设计者的思维了,而Factory Method对于顶层的抽象工厂(IObjectManager)来讲,是符合OCP的,它不负责具体实现,只需要发送命令,好比前面的集团公司总部和厨师总管,他们完全可以“坐吃山空”。

 

上面的代码很简单,就不具体解释了,输出结果为:

NPC Run
Building Run

 

Factory Method还可以做进一步演化,可以将所有的产品对象聚集在一起,例如有一个Object容器,当用户需要创建新的Object时,首先到容器里查找是否已经存在,如果存在则直接返回,不存在则创建一个此类型的Object,然后加到容器里。这样便能够循环利用,这也就是享元模式的特色。以后待谈及到享元模式时再具体讨论吧。在实际中,通常是多种模式相结合,已达到程序的需求。

 

工厂方法(Factory Method)的流程图示如下:

 

图2   工厂方法模式(Factory Method)

 

工厂方法就差不多这么多了,小结一下:

除了拥有简单工厂的优点之外,还弥补了简单工厂的OCP问题,各个工厂相对独立,在实际中可以确定为不同的工厂类型。这样也更符合实际,想想既然产品都可以各种类型,工厂自然也可以有各种类型了。

另外,在上面的简单工厂和工厂方法里,在用户使用工厂时,应该依耐于抽象层,而不应该依耐于具体的工厂,对于产品也一样,应该依耐于抽象产品编程,而不是具体的产品,如果依耐于具体的产品就失去了工厂的意义和多态的意义。

 

抽象工厂(Abstract Factory)

 

前面谈及CFightObjManger或CRegionObjManager时,谈到可能违反OCP的那种情况,也正好有了抽象工厂模式的影子,抽象工厂模式说专业一点就是解决产品族和产品等级结构之间的关系问题的。关于产品族和产品等级可以举个例子,如:游戏中的怪物和物品,通常情况下,副本中的怪物要比野外的怪物强(假设怪物也分为副本怪物和野外怪物),副本中的物品也比野外怪物爆出的物品强(假设物品也分副本和野外)。那么副本中的怪物和物品属于同一个产品族,野外的怪物和物品属于同一个产品族。而从纵向看,怪物属于一个产品等级,物品属于一个产品等级。如下图:

图3   产品族和产品等级

 

从图3中可知,之前的工厂方法是生产的同一个产品等级的产品,它们拥有共同的抽象基类。也就是同一系列的产品,例如CItem系列、CBuilding系列、CPlayer系列等。而Abstract Factory模式则是要创建同一个产品族的产品,例如副本产品和野外产品。同一个产品族通常不是同一系列的产品,因此, Abstract Factory包含多个产品的创建方法,从而又出现了OCP问题,当在一个产品族里增加一个新的产品时,对修改不封闭,也就是对增加产品等级的修改不封闭。只对增加一个产品族的修改封闭。这种情况也是必然,正所谓鱼和熊掌不可兼得。

 

再例如,我们常用的界面UI控件Button和Edit,为了表达多个平台下的界面,可分为windows、mac和unix等。于是有了WinButton、MacButton和UinxButton,WinEdit、MacEdit和UnixEdit。那么Button和Edit则分别处于两个不同的产品等级,产品族则有3个,因为有3种平台。如下图:

图4  产品等级与产品族示例

 

由此看来,产品族就好比将不同的产品进行捆绑式的生产,以达到特定的需求。好了,直接贴代码吧,如下:

以物品和怪物为例,我们将CItem和CMonster作为具体产品的基类,也可以进一步抽象,可视情况而定:

  1. const int IID_FBITEM       = 'FBIT';  
  2. const int IID_FIELDITEM    = 'FEIT';  
  3. const int IID_FBMONSTER    = 'FBMN';  
  4. const int IID_FIELDMONSTER = 'FEMN';  
  5.   
  6. class CFBItem : public CItem  
  7. {  
  8. public:  
  9.     CFBItem( void );  
  10.     ~CFBItem( void );  
  11.   
  12. public:  
  13.     void OnRun( void );  
  14.   
  15. protected:  
  16.     IObject* VCAST( const int iIID ){ return ( iIID == IID_ITEM || iIID == IID_FBITEM ) ? this : IObject::VCAST( iIID ); }  
  17. };  
  18.   
  19. class CFieldItem : public CItem  
  20. {  
  21. public:  

抱歉!评论已关闭.