程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> 設計模式-工廠方法 簡單工廠 抽象工廠 模板方法

設計模式-工廠方法 簡單工廠 抽象工廠 模板方法

編輯:C++入門知識

簡單工廠模式:
創建多種不同類型的產品,根據傳入參數的類型進行創建。
只有一個Creator方法,負責多種不同的產品的創建,傳入參數的類型來決定具體創建哪種產品,實現簡單,但是如果需要擴展產品的話,就需要修改Creator方法的實現。
有一個Pizza店,可以生產不同種類的Pizza,對於此代碼簡單如下:
//這是一個抽象的pizza,有很多不同種類的pizza,繼承於它。
[cpp]
class AbstractPizza 

public: 
    AbstractPizza(void); 
    virtual ~AbstractPizza(void); 
    virtual void Taste() = 0; 
    int m_nPizzaType; 
}; 

 class AbstractPizza
 {
 public:
  AbstractPizza(void);
  virtual ~AbstractPizza(void);
  virtual void Taste() = 0;
  int m_nPizzaType;
 };

 

//具體的pizza,繼承於抽象pizza。還有其他的多種不同類型的Pizza。
[cpp]
class SimplePizzaFactory 
    { 
    public: 
        enum PizzaType{ 
            CheesePizzaTpe, 
            GreekPizzaType, 
            PipperPizzaType, 
            //..可以繼續後續添加  
        }; 
        SimplePizzaFactory(void); 
        ~SimplePizzaFactory(void); 
        AbstractPizza* CreatePizzaByType(PizzaType type){ 
            switch (type) 
            { 
            case SimplePizzaFactory::CheesePizzaTpe: 
                { 
                    return new CheesePizza; 
                    //if you want, you can do additional initialization for new CheesePizza;  
                    //like:   
                    //AbstractPizza* pizza = new CheesePizza;  
                    //assert(pizza);  
                    //pizza->Initialize();  
                } 
            case SimplePizzaFactory::GreekPizzaType: 
                { 
                    return new GreekPizza; 
                    //if you want, you can do additional initialization for new CheesePizza;  
                } 
            case SimplePizzaFactory::PipperPizzaType: 
                { 
                    return new PipperPizza; 
                    //if you want, you can do additional initialization for new CheesePizza;  
                } 
            default: 
                break; 
            } 
        } 
}; 

class SimplePizzaFactory
 {
 public:
  enum PizzaType{
   CheesePizzaTpe,
   GreekPizzaType,
   PipperPizzaType,
   //..可以繼續後續添加
  };
  SimplePizzaFactory(void);
  ~SimplePizzaFactory(void);
  AbstractPizza* CreatePizzaByType(PizzaType type){
   switch (type)
   {
   case SimplePizzaFactory::CheesePizzaTpe:
    {
     return new CheesePizza;
     //if you want, you can do additional initialization for new CheesePizza;
     //like:
     //AbstractPizza* pizza = new CheesePizza;
     //assert(pizza);
     //pizza->Initialize();
    }
   case SimplePizzaFactory::GreekPizzaType:
    {
     return new GreekPizza;
     //if you want, you can do additional initialization for new CheesePizza;
    }
   case SimplePizzaFactory::PipperPizzaType:
    {
     return new PipperPizza;
     //if you want, you can do additional initialization for new CheesePizza;
    }
   default:
    break;
   }
  }
};


為了我們更好的管理Pizza的創建過程,一般我們會創建一個管理類,它負責創建不同種類的pizza產品。通過SimplePizzaFactory工廠的管理,我們通過傳入不同的類型就可以不同種類的pizza產品,外部的調用者只需要傳入類型,Creator方法就會返回正確的AbstractPizza的具體類型。甚至於你可以將SimplePizzaFactory定義為單例模式(如果工廠需要數據成員的話)便於以全局變量的方式使用。或者將CreatePizzaByType定義為靜態方法(如果沒有相關任何數據成員),這樣的話就不用創建任何工程對象,直接SimplePizzaFactory::CreatePizzaByType(nPizzaType)就可以,操作更簡答。它既然叫簡單工廠,確實足夠簡單,只有一個Creator方法(不過不能叫做工廠方法,注意沒有繼承),當有新的產品添加進來,必須需要修改Creator方法,以滿足新的產品創建的需要,不過說實話這種簡單工廠模式對於平常的很多程序都足夠。
[cpp]
class SimplePizzaFactory 
    { 
    public: 
        enum PizzaType{ 
            CheesePizzaTpe, 
            GreekPizzaType, 
            PipperPizzaType, 
            //..可以繼續後續添加  
        }; 
        SimplePizzaFactory(void); 
        ~SimplePizzaFactory(void); 
        AbstractPizza* CreatePizzaByType(PizzaType type){ 
            switch (type) 
            { 
            case SimplePizzaFactory::CheesePizzaTpe: 
                { 
                    return new CheesePizza; 
                    //if you want, you can do additional initialization for new CheesePizza;  
                    //like:   
                    //AbstractPizza* pizza = new CheesePizza;  
                    //assert(pizza);  
                    //pizza->Initialize();  
                } 
            case SimplePizzaFactory::GreekPizzaType: 
                { 
                    return new GreekPizza; 
                    //if you want, you can do additional initialization for new CheesePizza;  
                } 
            case SimplePizzaFactory::PipperPizzaType: 
                { 
                    return new PipperPizza; 
                    //if you want, you can do additional initialization for new CheesePizza;  
                } 
            default: 
                break; 
            } 
        } 
}; 

class SimplePizzaFactory
 {
 public:
  enum PizzaType{
   CheesePizzaTpe,
   GreekPizzaType,
   PipperPizzaType,
   //..可以繼續後續添加
  };
  SimplePizzaFactory(void);
  ~SimplePizzaFactory(void);
  AbstractPizza* CreatePizzaByType(PizzaType type){
   switch (type)
   {
   case SimplePizzaFactory::CheesePizzaTpe:
    {
     return new CheesePizza;
     //if you want, you can do additional initialization for new CheesePizza;
     //like:
     //AbstractPizza* pizza = new CheesePizza;
     //assert(pizza);
     //pizza->Initialize();
    }
   case SimplePizzaFactory::GreekPizzaType:
    {
     return new GreekPizza;
     //if you want, you can do additional initialization for new CheesePizza;
    }
   case SimplePizzaFactory::PipperPizzaType:
    {
     return new PipperPizza;
     //if you want, you can do additional initialization for new CheesePizza;
    }
   default:
    break;
   }
  }
};

 

工廠方法模式:
對擴展開放,對修改關閉,對於上面的簡單工廠,creator方法以後可能需要修改,因此我們可以通過將要改的方面單獨提煉出來。這就構造出了工廠方法模式。有一個抽象的工廠方法,它的出現將外部的調用統一化,由具體的工廠負責產品的創建過程。工廠方法模式就是將產品的創建過程延遲到子類,由子類負責具體的產品創建,而且一種工廠只生產一種產品。具體工廠和具體產品一一對應,抽象的Creator方法和抽象的產品對應。
這經常用在抽象類中,專為創建對象定義一個方法。子類就可以覆蓋這個方法來定義要創建的特定對象。通常與模板方法和並使用,模板方法在定義模板算法時一般需要先創建產品,然後再利用產品的方法創建一個流程。

一個抽象產品類,可以派生出多個具體產品類。
一個抽象工廠類,可以派生出多個具體工廠類。
每個具體工廠類只能創建一個具體產品類的實例。

還用上面的例子,現在首先需要一個抽象的Creator方法,你可以把它看成一個抽象工廠,其實也是它是一個特殊的抽象工廠,只生產一種產品.
不過下面的比普通的工廠方法模式又稍微高級了一點,它是參數化的工廠方法模式,靈活性更大。
[cpp]
class PizzaFactory 
    { 
    public: 
        enum PizzaType{ 
            CheesePizzaTpe, 
            GreekPizzaType, 
            PipperPizzaType, 
        }; 
        PizzaFactory(void); 
        ~PizzaFactory(void); 
        AbstractPizza* PizzaFactory(PizzaType type)(); 
}; 
     
    //具體的工廠,負責生產BeiJing的pizza。  
    class BeiJingPizzaFactory : public PizzaFactory 
    { 
    public: 
 
 
        BeiJingPizzaFactory(void); 
        ~BeiJingPizzaFactory(void); 
        AbstractPizza* CreatePizzaByType(PizzaType type)(){ 
            switch (type){ 
                case PizzaFactory::CheesePizzaTpe: 
                    return new BeiJingCheesePizza; 
            case PizzaFactory::GreekPizzaType: 
                    return new BeiJingGreekPizza; 
            case PizzaFactory::PipperPizzaType: 
                    return new BeiJingPipperPizza; 
            default: 
                return NULL; 
            }; 
        } 
    }; 

class PizzaFactory
 {
 public:
  enum PizzaType{
   CheesePizzaTpe,
   GreekPizzaType,
   PipperPizzaType,
  };
  PizzaFactory(void);
  ~PizzaFactory(void);
  AbstractPizza* PizzaFactory(PizzaType type)();
};
 
 //具體的工廠,負責生產BeiJing的pizza。
 class BeiJingPizzaFactory : public PizzaFactory
 {
 public:


  BeiJingPizzaFactory(void);
  ~BeiJingPizzaFactory(void);
  AbstractPizza* CreatePizzaByType(PizzaType type)(){
   switch (type){
    case PizzaFactory::CheesePizzaTpe:
     return new BeiJingCheesePizza;
   case PizzaFactory::GreekPizzaType:
     return new BeiJingGreekPizza;
   case PizzaFactory::PipperPizzaType:
     return new BeiJingPipperPizza;
   default:
    return NULL;
   };
  }
 };

關於BeiJingCheesePizza, BeiJingGreekPizza, BeiJingPipperPizza這些就不寫了,就是繼承於抽象的Pizza。

對擴展開放,對修改關閉:
如果再有天津的,河南的,意大利的等等Pizza。通過使用工廠方法模式,以後即使再有其他地區的pizza店,只需要添加另外的一個具體工廠和具體的產品就行了。不要糾結於增加新的PizzaType怎麼辦?工廠方法模式專注的點是有新地區的產品,而不是有新的PizzaType。因為最基本的工廠方法模式是一個工廠一個產品,一一對應。如果想著眼於type而忽略地區,可以考慮一種PizzaType一個Pizza工廠,那樣添加了新的type,就添加新的工廠和產品就可以了,完美符合對擴展開放,對修改關閉。
子類實例化:
工廠方法模式對外部提供的是一個工廠方法,它是一個抽象接口,這樣外部依賴的就是抽象而不是具體,減少代碼耦合性。將具體的new的操作放到子類工廠來實現。
應用:
說實話,找應用費了好久,畢竟整天Pizza,Pizza的很難給我們以啟發,僅僅是知道模式,而沒有看到它的巨大潛力和價值。
學習MFC的都知道Document和Application的關系。不同的Application對應不同的Document。app負責創建doc。app就是工廠,doc就是產品,一個工廠一個產品。

[cpp]
//App是工廠,它保存著創建的產品  
    //App  
    class Application 
    { 
    public: 
        void OpenDocument(){//模板方法  
            m_pDoc = CreateDocment(); 
            m_pDoc->Open(); 
            m_pDoc->Read(); 
        } 
        void CloseDocument(){//模板方法  
            m_pDoc->Write(); 
            m_pDoc->Close(); 
        } 
    private: 
        virtual Document* CreateDocment() = 0;//工廠方法  
    private: 
        Document* m_pDoc;//這個  
    } 
     
    //抽象產品類,文檔可以打開關閉,讀寫。  
    class Document  
    { 
    public: 
        void Open(); 
        void Close(); 
        void Read(); 
        void Write(); 
    } 

//App是工廠,它保存著創建的產品
 //App
 class Application
 {
 public:
  void OpenDocument(){//模板方法
   m_pDoc = CreateDocment();
   m_pDoc->Open();
   m_pDoc->Read();
  }
  void CloseDocument(){//模板方法
   m_pDoc->Write();
   m_pDoc->Close();
  }
 private:
  virtual Document* CreateDocment() = 0;//工廠方法
 private:
  Document* m_pDoc;//這個
 }
 
 //抽象產品類,文檔可以打開關閉,讀寫。
 class Document
 {
 public:
  void Open();
  void Close();
  void Read();
  void Write();
 }

解釋:
上面兩個類一看到就會有種欣喜的感覺,將模板方法和工廠方法完美的組合了起來。工廠方法關心的是創建對象,由具體的工廠MyApp負責創建實現具體的產品MyDocument.同時,模板方法OpenDocument面向抽象的創建接口編程,負責定義了一套算法,子類繼承了Application,就繼承了一套算法,子類不用關心算法執行的步驟,子類只需要實現方法,父類負責調用子類的方法。
像經常看到的狀態機代碼,狀態機的跳轉流程是由預先定義的流程定義的,但是OnStateEnter和OnStateExit這樣的方法的實現是由具體應用定義的。父類負責調用子類OnStateEnter和OnStateExit方法的具體的實現,模板方法的典型應用。

抽象工廠:
抽象工廠關注的是創建一系列的產品,它是使用工廠方法實現的,不過是擁有多個工廠方法。
代碼就不寫了。
 簡單工廠能把具體實現包裝起來,讓客戶端真正達到面向接口編程
工廠方法可以在高層進行編碼,讓服務端的產品線真正達到面向接口編程
抽象工廠能聚合整個產品簇,讓整個服務端的多個產品線真正達到面向接口編程
模板方法同樣是在高層進行編碼,也同樣是面向接口編程。
但工廠方法及抽象工廠方法著重抽象的是產品,而模板方法著重抽象的是步驟。
而我們通常會兩者一起結合起來使用。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved