設計模式-工廠方法模式

20191030175212.jpg

概念

工廠方法模式(Factory Method Pattern)又稱工廠模式,也叫虛擬構造器(Virtual Constructor)模式或者多態工廠(Polymorphic Factory)模式,在工廠方法模式中,工廠父類負責定義建立產品對象的公共接口,而工廠子類則負責生成具體的產品對象,這樣作的目的是將產品類的實例化操做延遲到工廠子類中完成,即經過工廠子類來肯定究竟應該實例化哪個具體產品類。
工廠方法,能夠理解爲一種將實例化邏輯委託給子類的方法,父基類提供共有實現,派生類完成個性化定製實現ios

使用時機

若是有這樣的場景,存在部分共有的功能邏輯,可是在運行時又須要動態決定使用哪一個子類的邏輯實現,也就是說
須要動態根據需求選擇不一樣的子類實現,這個時候可使用工廠方法。
建議在如下狀況下選用工廠方法模式。c++

  • 若是一個類須要建立某個接口的對象,可是又不知道具體的實現,這種狀況能夠選用工廠方法模式,把建立對象的工做延遲到子類中去實現。
  • 若是一個類自己就但願由他的子類來建立所需的對象的時候,應該使用工廠方法模式。

與簡單工廠的區別

初接觸工廠方法模式,會感受,「這不是跟簡單工廠同樣嗎」golang

從本質上講,他們確實是很是相似的,在具體實現上都是「選擇實現」。可是也存在不一樣點,簡單工廠是直接在工廠類裏進行「選擇實現」;而工廠方法會把這個工做延遲到子類來實現,工廠類裏面使用工廠方法的地方是依賴於抽象而不是具體的實現,從而使得系統更加靈活,具備更好的可維護性和可擴展性。shell

從某個角度講,能夠認爲簡單工廠就是工廠方法模式的一種特例,所以他們的本質是相似的。ide

具體的舉例,簡單工廠實例中,客戶就是要一個門,而不關心建立過程,最後實際創造的是一個木門,這個比較尷尬,若是客戶要的是個鐵門呢?因此在這個例子中,也是存在兩維抽象的,一是「門」這個類型的抽象,二是「造門」這個方法的抽象。簡單工廠只作到了前者,而沒有給出後者的解決方案,若是看咱們按照工廠方法的思路,將門工廠造門這件事進行細分,木門交給木門工廠,鐵門交給鐵門工廠,這就是工廠方法的實現,客戶須要先制定委託對象,而沒必要關係具體怎麼造門。函數

具體實現

C++實現

結構圖

uml1.png

代碼實現

#include <iostream>

 class IInterviewer
 {
     public:
         virtual void askQuestions() = 0;
 };

 class Developer : public IInterviewer
 {
     public:
         void askQuestions() override {
             std::cout << "Asking about design patterns!" << std::endl;
         }
 };

 class CommunityExecutive : public IInterviewer
 {
     public:
         void askQuestions() override {
             std::cout << "Asking about community building!" << std::endl;
         }
 };

 class HiringManager
 {
     public:
         void takeInterview() {
             IInterviewer* interviewer = this->makeInterviewer();
             interviewer->askQuestions();
         }

     protected:
         virtual IInterviewer* makeInterviewer() = 0;
 };

 template <typename Interviewer>
 class OtherManager : public HiringManager {
     protected:
         IInterviewer* makeInterviewer() override {
             return new Interviewer();
         }
 };

 int main()
 {
     HiringManager* devManager = new OtherManager<Developer>();
     devManager->takeInterview();

     HiringManager* marketingMnager = new OtherManager<CommunityExecutive>();
     marketingMnager->takeInterview();
     return 0;
 }

運行結果測試

g++ -o factory-method factory-method.cpp --std=c++11
./factory-method
Asking about design patterns!
Asking about community building!

總結

IInterviwer爲基礎類,定義爲一個虛基類,具體派生出了Devoloper和CommunityExecutive兩個實現子類;
HiringManager爲工廠基類,定義爲一個虛基類,OtherManager爲具體實現的派生類,根據傳入的template type,返回不一樣的建立對象。優化

Golang實現

結構圖

factory-method.png

代碼實現

package factory_method


//Operator是被封裝的接口
type Operator interface {
    SetA(int)
    SetB(int)
    Result() int
}

//工廠接口
type OperatorFactory interface {
    Create() Operator
}

//OperatorBase是Operator接口實現的基類,封裝公有方法
type OperatorBase struct {
    a,b int
}

//SetA方法實現
func (op *OperatorBase) SetA(aValue int) {
    op.a = aValue
}

//SetB方法實現
func (op *OperatorBase) SetB(bValue int) {
    op.b = bValue
}

//下面是分別構造不一樣類型Operator以及對應生產的工廠類

//加法工廠類
type PlusOperatorFactory struct {

}

//加法工廠類實現工廠接口
func (pof PlusOperatorFactory) Create() Operator {
    return &PlusOperator{}
}

//加法類
type PlusOperator struct {
    OperatorBase
}

//加法類實現Operator接口的Result函數
func (pop *PlusOperator) Result() int {
    return pop.a + pop.b
}

//減法工廠類
type MinusOperatorFactory struct {

}

//減法工廠類實現工廠接口
func (mof MinusOperatorFactory) Create() Operator {
    return &MinusOperator{}
}

//減法類
type MinusOperator struct {
    OperatorBase
}

//減法類實現Operator接口的Result函數
func (mop *MinusOperator) Result() int {
    return mop.a - mop.b
}

測試用例ui

package factory_method

import "testing"

func TestPlusOperator_Result(t *testing.T) {
     pof := PlusOperatorFactory{}
     pop := pof.Create()
     pop.SetA(1)
     pop.SetB(2)
     if pop.Result() != 3 {
        t.Fatal("test plus operator factory failed")
     }
}

func TestMinusOperator_Result(t *testing.T) {
    mof := MinusOperatorFactory{}
    mop := mof.Create()
    mop.SetA(2)
    mop.SetB(1)
    if mop.Result() != 1 {
        t.Fatal("test minus operator factory failed")
    }
}

運行結果this

go test -v factory-method.go factory-method_test.go
=== RUN   TestPlusOperator_Result
--- PASS: TestPlusOperator_Result (0.00s)
=== RUN   TestMinusOperator_Result
--- PASS: TestMinusOperator_Result (0.00s)
PASS
ok      command-line-arguments  0.734s

優化後更實用的版本

func LoadFactory(name string) OperatorFactory {
    switch name {
    case "plus":
        return PlusOperatorFactory{}
    case "minus":
        return MinusOperatorFactory{}
    default:
        return PlusOperatorFactory{}
    }
}

測試用例

......
pof := LoadFactory("plus")
......

工廠方法模式的思考

工廠方法模式的缺點

  • 在添加新產品時,須要編寫新的具體產品類,並且還須要提供與之對應的具體工廠類,系統中類的個數將成對增長,在必定程度上增長了系統的複雜度,有更多的類須要編譯和運行,會給系統帶來一些額外的開銷
  • 因爲考慮到系統的可擴展性,須要引入抽象層,在客戶端代碼中均使用抽象層進行定義,增長了系統的抽象性和理解難度。
相關文章
相關標籤/搜索