设计模式之简单工厂

来源:互联网 发布:北大青鸟网络培训学校 编辑:程序博客网 时间:2024/06/09 16:18
       GoF的设计模式一经推出,就引起了各路诸侯的严重关注。从JAVA到C#再到C++,甚至连面向过程为主的C都想染指一番。今天,就从C#出发,推导出C++的代码,并用一个C++的ATM模拟程序来实作(这个词好像是从侯捷先生那学来的,如果我记错了,希望他不会怪我,呵呵)。
      我们首先看看简单工厂来描述一个四则运算的UML类图。

      呵呵,发现在Ubuntu下使用Firefox上传图片会失败。看来在中国,使用Linux确实面临不少障碍!只能切换到Window Xp下再试一下了。后来发现原来是我把图片格式搞错了。CSDN支持的格式为gif,jpg,png,我开始传的是bmp。现在改为jpg就好了,错怪它了。
      从图中信息可知,运算类为一个抽象基类,声明了一个基本接口,和两个运算参数,这里为double类型。其实可以用模板方式来扩展该基类,这样就不仅仅处理double类型了。C++代码如下:
  1. //Operation.h
  2. /** /brief COperator
  3.  * Description:运算基类
  4.  */
  5. template<typename T>
  6. class COperator
  7. {
  8. private:
  9.     T NumberA;    /*!< 第一个运算变量 */
  10.     T NumberB;    /*!< 第二个运算变量,处理两个相同类型的运算 */
  11. public:
  12.     COperator();
  13.     virtual ~COperator() = 0;    /*!< 没什么好说的,必须的 */
  14.     T GetResult() = 0;           /*!< 抽象类接口 */
  15.     void SetNumberA(T t);
  16.     void SetNumberB(T t);
  17. };
      下面是各运算子类:
  1. // OperationChild.h
  2. #include "Operation.h"
  3. /** /brief COperatorAdd
  4.  * Description:加法运算子类
  5.  */
  6. template<typename T>
  7. class COperatorAdd : public COperator
  8. {
  9. public:
  10.     COperatorAdd();
  11.     ~COperatorAdd();
  12.     virtual T GetResult();    /*!< 在cpp文件中实现,此略 */
  13. };
  14. /** /brief COperatorSub
  15.  * Description:减法运算子类
  16.  */
  17. template<typename T>
  18. class COperatorSub : public COperator
  19. {
  20. public:
  21.     COperatorSub();
  22.     ~COperatorSub();
  23.     virtual T GetResult();    /*!< 在cpp文件中实现,此略 */
  24. };
  25. /** /brief COperatorMul
  26.  * Description:乘法运算子类
  27.  */
  28. template<typename T>
  29. class COperatorMul : public COperator
  30. {
  31. public:
  32.     COperatorMul();
  33.     ~COperatorMul();
  34.     virtual T GetResult();    /*!< 在cpp文件中实现,此略 */
  35. };
  36. /** /brief COperatorDiv
  37.  * Description:除法运算子类
  38.  */
  39. template<typename T>
  40. class COperatorDiv : public COperator
  41. {
  42. public:
  43.     COperatorDiv();
  44.     ~COperatorDiv();
  45.     virtual T GetResult();    /*!< 在cpp文件中实现,此略 */
  46.     /*!< 记得在此接口实现中要判断除数为零的情况 */
  47. };
      接下来是简单工厂类:
  1. // OperatorFactory.h
  2. #include "Operation.h"
  3. /** /brief COperatorFactory
  4.  * Description:简单工厂类,用于产生运算对象
  5.  */
  6. enum operator_sign
  7. {
  8.     SIGN_ADD,
  9.     SIGN_SUB,
  10.     SIGN_MUL,
  11.     SIGN_DIV,
  12. };
  13. class COperatorFactory
  14. {
  15. private:
  16.     COperator* m_pOper;
  17. public:
  18.     COperatorFactory();
  19.     ~COperatorFactory();
  20.     /** /brief CreateOperator接口
  21.      * 接收输入的运算符,生成运算对象
  22.      */
  23.     COperator* CreateOperator(operator_sign param = SIGN_ADD);
  24. };
      以上代码,我都没有写出实现部分,大家可以自己完成这部分,很简单的。下面来分析一下ATM模拟程序中可以使用该设计模式的部分。熟悉ATM程序的人员知道,在ATM交易过程中,查询、取款、转帐、改密等等交易其实都是类似的,唯一不同的地方在于每个交易数据包中个别域数据不相同;或者是某些域只有某个交易才有,其他交易数据包中没有。每增加一个交易,就必须配置一个交易数据,同时增加处理该交易数据的处理部分。因历史原因,这些处理交易数据的部分都在一个地方,而每个银行的交易有不尽相同。所以ATM软件在每个银行实施其实都变成了一个项目,而不是产品。如果能将各交易单独提出来做成子类处理,这样,可以形成一个交易子类库。每次根据不同银行的不同交易,找出对应的交易子类就可以满足客户需求,代码也不需要作大的变动。
      下面按照上面的思路来仿照简单工厂类来设计ATM模拟软件的交易处理:
C#版:
  1. // transaction.cs
  2. public class TransactionBase
  3. {
  4.     // 产生交易数据包接口
  5.     public virtual string GenPacket
  6.     {
  7.         return "";
  8.     }
  9.    
  10.     // 解析交易数据包接口
  11.     public virtual bool ParsePacket(string strPacket)
  12.     {
  13.         return true;
  14.     }
  15. }
  1. // QueryBalance.cs
  2. class QueryBalance : TransactionBase
  3. {
  4.     // 产生的查询余额交易数据包处理
  5.     public override string GenPacket()
  6.     {
  7.         // ...
  8.     }
  9.     // 解析查询余额交易数据包处理
  10.     public override bool ParsePacket(string strPacket)
  11.     {
  12.         // ...
  13.     }
  14. }
  1. // transactionFactory.cs

  2. public class TransactionFactory
  3. {
  4.     public static TransactionBase CreateTransaction(string transCode)
  5.     {
  6.         TransactionBase trans = null;
  7.         // 交易类型判断分支
  8.         switch(transCode)
  9.         {
  10.         case "123456":    /*!< 查询余额交易 */
  11.             trans = new QueryBalance();
  12.             break;
  13.         // ...
  14.         default:
  15.             // ...
  16.             break;
  17.         }
  18.         return trans;
  19.     }
  20. }
      客户端调用:
  1. // client.cs
  2. TransactionBase trans;
  3. trans = TransactionFactory.CreateTransaction("123456");
  4. string packetData = trans.GenPacket();    // 产生交易数据包
  5. packetData.ParsePacket(recvPacket);    // 解析交易数据包

C++版:
  1. // transaction.h
  2. #include <string>
  3. using std::string;
  4. /** /brief CTransaction
  5.  * Description:交易基类
  6.  */
  7. class CTransaction
  8. {
  9. public:
  10.     CTransaction();
  11.     virtual ~CTransaction() = 0;
  12.     /*!< 组交易数据报 */
  13.     string GenPacket() = 0;
  14.     /*!< 解析收到的交易数据报 */
  15.     bool ParsePacket(const string& strPacket) = 0;
  16. };
      交易处理子类:
  1. // query.h
  2. // 查询其实又可以分为很多种查询交易,如查询余额,查询明细、查询第三方交// 易等信息的交易。这里我只简单的处理查询余额。

  3. #include "transaction.h"
  4. #include <string>
  5. using std::string;
  6. class CQueryBalance : public CTransaction
  7. {
  8. private:
  9. public:
  10.     CQueryBalance();
  11.     ~CQueryBalance();
  12.     string GenPacket();
  13.     bool ParsePacket(const string& strPacket);
  14. };
      查询余额子类的实现:
  1. #include "query.h"
  2. CQueryBalance::CQueryBalance()
  3. {
  4. }
  5. CQueryBalance::~CQueryBalance()
  6. {
  7. }
  8. string CQueryBalance::GenPacket()
  9. {
  10.     /*!< 组交易代码、交易日期、交易时间等信息到string变量 */
  11.     string strPacketData;
  12.     // ......
  13.     return strPacketData;
  14. }
  15. bool CQueryBalance::ParsePacket(const string& strPacket)
  16. {
  17.     /*!< 解析出数据包中各域的数据,并作相应处理 */
  18.     //......
  19.     return true;
  20. }
      其他交易类型可仿照完成。此略!
      下面是简单工厂类的声明:
  1. // transactionFactory.h
  2. /** /brief CTransactionFactory
  3.  * Description: ATM交易处理简单工厂类
  4.  */
  5. #include "transcation.h"
  6. #include <string>
  7. using std::string;
  8. class CTransactionFactory
  9. {
  10. private:
  11.     CTransaction* m_pTrans;
  12. public:
  13.     CTransactionFactory();
  14.     ~CTransactionFactory();
  15.     CTransaction* CreateTransaction(const string& transCode);
  16. };
      对应的实现文件:
  1. // transactionFactory.cpp
  2. CTransactionFactory::CTransactionFactory()
  3. {
  4. }

  5. CTransactionFactory::~CTransactionFactory()
  6. {
  7. }

  8. CTransaction* CTransactionFactory::CreateTransaction(const string& transCode)
  9. {
  10.     if (transCode == "123456")
  11.     {
  12.         // 生长查询余额交易的对象
  13.         m_pTrans = new CQueryBalance();
  14.     }
  15.     else if ()    // 其他交易代码
  16.     {
  17.         // ...
  18.     }
  19.     return m_pTrans;
  20. }
      客户端调用代码如下:
  1. // Client.cpp
  2. #include "transaction.h"
  3. #include "transactionFactory.h"
  4. void Function()
  5. {
  6.     CTransaction* pTrans = CreateTransaction("123456");
  7.     pTrans->GenPacket();  /*!< 生成交易数据包 */
  8.     pTrans->ParsePacket(strPacket);  /*!< 解析交易数据包 */
  9.     delete pTrans;    /*!< 关键!千万别忘了! */

      以后每增加新的交易,则只需要增加交易子类和修改transactionFactory.cpp文件即可。客户调用代码和主体结构不需要作太大变动。