工廠模式(Factory Pattern)

提出一個問題

模式的問題:你如何能輕鬆方便地構造對象實例,而沒必要關心構造對象實例的細節和複雜過程呢?ios

解決方案:創建一個工廠來建立對象。 固然也能夠根據不一樣的狀況,採用建造者模式或者原型模式,總之,你須要另外一個建立者角色對象來幫助你產生建立構造對象實例。這裏咱們將工廠模式。c++

工廠模式能夠分爲三類:設計模式

  • 簡單工廠模式(Simple Factory)
  • 工廠方法模式(Factory Method)
  • 抽象工廠模式(Abstract Factory)

這三種模式從上到下逐步抽象,而且更具通常性。GOF在《設計模式》一書中將工廠模式分爲兩類:工廠方法模式(Factory Method)與抽象工廠模式(Abstract Factory)。將簡單工廠模式(Simple Factory)看爲工廠方法模式的一種特例,二者歸爲一類。bash

模式 描述
工廠方法模式 一個抽象產品類,能夠派生出多個具體產品類。一個抽象工廠類,能夠派生出多個具體工廠類。每一個具體工廠類只能建立一個具體產品類的實例。
抽象工廠模式 多個抽象產品類,每一個抽象產品類能夠派生出多個具體產品類。一個抽象工廠類,能夠派生出多個具體工廠類。每一個具體工廠類能夠建立多個具體產品類的實例。

工廠方法模式與抽象工廠模式的區別——工廠方法模式只有一個抽象產品類,而抽象工廠模式有多個。 工廠方法模式的具體工廠類只能建立一個具體產品類的實例,而抽象工廠模式能夠建立多個。 。函數

簡單工廠模式

簡單工廠模式又稱靜態工廠方法模式。從命名上就能夠看出這個模式必定很簡單。它存在的目的很簡單:定義一個用於建立對象的接口。 單元測試

這裏寫圖片描述
適用場合:

  1. 在程序中,須要建立的對象不少,致使對象的new操做多且雜時,須要使用簡單工廠模式;
  2. 因爲對象的建立過程是咱們不須要去關心的,而咱們注重的是對象的實際操做,因此,咱們須要分離對象的建立和操做兩部分,如此,方便後期的程序擴展和維護。
#include "stdafx.h"
#include <iostream>
#include <vector>
using namespace std;

typedef enum ProductTypeTag
{
	TypeA,
	TypeB,
	TypeC
}PRODUCTTYPE;

// Here is the product class
class Product {
public:
	virtual void Show() = 0;
};

class ProductA : public Product
{
public:
	void Show() {
		cout<<"I'm ProductA"<<endl;
	}
};

class ProductB : public Product
{
public:
	void Show() {
		cout<<"I'm ProductB"<<endl;
	}
};

class ProductC : public Product
{
public:
	void Show() {
		cout<<"I'm ProductC"<<endl;
	}
};

// Here is the Factory class
class Factory {
public:
	Product* CreateProduct(PRODUCTTYPE type) {
		switch (type)
		{
		case TypeA:
			return new ProductA();

		case TypeB:
			return new ProductB();

		case TypeC:
			return new ProductC();

		default:
			return NULL;
		}
	}
};
複製代碼
#include<memory>
#include "simple_factory.h"
using namespace std;

int main() {
	// First, create a factory object
	std::unique_ptr<Factory> ProductFactory(new Factory);

	std::unique_ptr<Product> productObjA(ProductFactory->CreateProduct(TypeA));
	productObjA->Show();

	std::unique_ptr<Product> productObjB(ProductFactory->CreateProduct(TypeB));
	productObjB->Show();

	std::unique_ptr<Product> productObjC(ProductFactory->CreateProduct(TypeC));
	productObjC->Show();

	return 0;
}
複製代碼

工廠方法模式

以前講到了簡單工廠模式,因爲簡單工廠模式的侷限性,好比:工廠如今能生產ProductA、ProductB和ProductC三種產品了,此時,須要增長生產ProductD產品;那麼,首先是否是須要在產品枚舉類型中添加新的產品類型標識,而後,修改Factory類中的switch結構代碼。是的,這種對代碼的修改,對原有代碼的改動量較大,易產生編碼上的錯誤(雖然很簡單,若是工程大了,出錯也是在所不免的!)。這種對代碼的修改是最原始,最野蠻的修改,本質上不能稱之爲對代碼的擴展。同時,因爲對已經存在的函數進行了修改,那麼之前進行過的測試,都將是無效的,全部的測試,都將須要從新進行,全部的代碼都須要進行從新覆蓋。這種,增長成本,不能提升效率的事情,在公司是絕對不容許的。出於種種緣由,簡單工廠模式,在實際項目中使用的較少。那麼該怎麼辦?怎麼辦呢?須要對原有代碼影響降到最小,同時能對原有功能進行擴展。 測試

這裏寫圖片描述
工廠方法模式,就隆重登場了。它只是對簡單工廠模式的擴展,在GOF的介紹中,它們是合併在一塊兒的。 工廠方法模式是在簡單工廠模式的基礎上,對「工廠」添加了一個抽象層。將工廠共同的動做抽象出來,做爲抽象類,而具體的行爲由子類自己去實現,讓子類去決定生產什麼樣的產品。如圖,FactoryA專心負責生產ProductA,FactoryB專心負責生產ProductB,FactoryA和FactoryB之間沒有關係;若是到了後期,若是須要生產ProductC時,咱們則能夠建立一個FactoryC工廠類,該類專心負責生產ProductC類產品。因爲FactoryA、FactoryB和FactoryC之間沒有關係,當加入FactoryC加入時,對FactoryA和FactoryB的工做沒有產生任何影響,那麼對代碼進行測試時,只須要單獨對FactoryC和ProductC進行單元測試,而FactoryA和FactoryB則不用進行測試,則可省去大量無趣無味的測試工做。

適用場合

工廠方法模式的意義是定義一個建立產品對象的工廠接口,將實際建立工做推遲到子類當中。核心工廠類再也不負責產品的建立,這樣核心類成爲一個抽象工廠角色,僅負責具體工廠子類必須實現的接口,這樣進一步抽象化的好處是使得工廠方法模式可使系統在不修改具體工廠角色的狀況下引進新的產品。ui

  1. 在設計的初期,就考慮到產品在後期會進行擴展的狀況下,可使用工廠方法模式;
  2. 產品結構較複雜的狀況下,可使用工廠方法模式;

因爲使用設計模式是在詳細設計時,就須要進行定奪的,因此,須要權衡多方面的因素,而不能爲了使用設計模式而使用設計模式。編碼

代碼示例(C++)

#include "stdafx.h"
#include <iostream>
#include <vector>
using namespace std;

// Here is the product class
class Product
{
public:
	virtual void Show() = 0;
};

class ProductA : public Product
{
public:
	void Show()
	{
		cout<<"I'm ProductA"<<endl;
	}
};

class ProductB : public Product
{
public:
	void Show()
	{
		cout<<"I'm ProductB"<<endl;
	}
};

class ProductC : public Product
{
public:
	void Show()
	{
		cout<<"I'm ProductC"<<endl;
	}
};

// Here is the Factory class
class Factory
{
public:
	virtual Product* CreateProduct()=0;

};

class FactoryA:public Factory
{
public:
	Product* CreateProduct()
	{
		return new ProductA;
	}
};

class FactoryB:public Factory
{
public:
	Product* CreateProduct()
	{
		return new ProductB;
	}
};

class FactoryC:public Factory
{
public:
	Product* CreateProduct()
	{
		return new ProductC;
	}
};
複製代碼
#include<memory>
#include "factory.h"
using namespace std;

int main(){
	// First, create a factory object
	Factory* ProductFactory=new FactoryA;

	std::unique_ptr<Product> productObjA(ProductFactory->CreateProduct());
	productObjA->Show();

	ProductFactory = new FactoryB;
	std::unique_ptr<Product> productObjB(ProductFactory->CreateProduct());
	productObjB->Show();

	ProductFactory = new FactoryC;
	std::unique_ptr<Product> productObjC(ProductFactory->CreateProduct());
	productObjC->Show();

	delete ProductFactory;

	return 0;
}
複製代碼

這樣後期若是想增長產品D或者刪除已有產品C對原有程序改動(範圍)都很是小。spa

抽象工廠模式

以前講到了工廠方法模式,咱們可能會想到,後期產品會愈來愈多了,創建的工廠也會愈來愈多,工廠進行了增加,工廠變的凌亂而難於管理;因爲工廠方法模式建立的對象都是繼承於Product的,因此工廠方法模式中,每一個工廠只能建立單一種類的產品,當須要生產一種全新的產品(不繼承自Product)時,發現工廠方法是愛莫能助。

舉個例子來講:一個顯示器電路板廠商,旗下的顯示器電路板種類有非液晶的和液晶的;這個時候,廠商建造兩個工廠,工廠A負責生產非液晶顯示器電路板,工廠B負責生產液晶顯示器電路板;工廠一直就這樣運行着。有一天,總經理髮現,直接生產顯示器的其他部分也挺掙錢,因此,總經理決定,再創建兩個工廠C和D;C負責生產非液晶顯示器的其他部件,D負責生產液晶顯示器的其他部件。此時,旁邊參謀的人就說了,經理,這樣作很差,咱們能夠直接在工廠A中添加一條負責生產非液晶顯示器的其他部件的生產線,在工廠B中添加一條生產液晶顯示器的其他部件的生產線,這樣就能夠不用增長廠房,只用將現有廠房進行擴大一下,同時也方便工廠的管理,並且生產非液晶顯示器電路板的技術人員對非液晶顯示的其他部件的生產具備指導的做用,生產液晶顯示器電路板也是同理。總經理髮現這是一個不錯的主意。

再回到軟件開發的過程當中來,工廠A和B就是以前所說的設計模式——工廠方法模式;總經理再次創建工廠C和D,就是重複設計模式——工廠方法模式,只是生產的產品不一樣罷了。這樣作的弊端就如參謀所說的那樣,增長了管理成本和人力成本。在面向對象開發的過程當中,是很注重對象管理和維護的,對象越多,就越難進行管理和維護;若是工廠數量過多,那麼管理和維護的成本將大大增長;雖然生產的是不一樣的產品,可是能夠兩者之間是有微妙的關係的,如參謀所說,技術人員的一些技術經驗是能夠借鑑的,這就至關於同一個類中的不一樣對象,之間是能夠公用某些資源的。那麼,增長一條流水線,擴大廠房,固然是最好的主意了。

實際問題已經獲得瞭解決,那麼如何使用設計模式模擬這個實際的問題呢?那就是接下來所說的抽象工廠模式。

抽象工廠模式,就是工廠方法模式的擴展和延伸,可是抽象工廠模式,更有通常性和表明性;它具備工廠方法具備的優勢,也增長了解決實際問題的能力。

這裏寫圖片描述
如圖所示, 抽象工廠模式,就比如是兩個工廠方法模式的疊加。抽象工廠建立的是一系列相關的對象,其中建立的實現其實就是採用的工廠方法模式。在工廠Factory中的每個方法,就比如是一條生產線,而生產線實際須要生產什麼樣的產品,這是由Factory1和Factory2去決定的,這樣便延遲了具體子類的實例化;同時集中化了生產線的管理,節省了資源的浪費。

適用場合

工廠方法模式適用於產品種類結構單一的場合,爲一類產品提供建立的接口;而抽象工廠方法適用於產品種類結構多的場合,主要用於建立一組(有多個種類)相關的產品,爲它們提供建立的接口;就是當具備多個抽象角色時,抽象工廠即可以派上用場。

代碼示例

#pragma once
#include <iostream>
using namespace std;

// Product A
class ProductA {
public:
	virtual void Show() = 0;
};

class ProductA1 : public ProductA
{
public:
	void Show() {
		cout << "I'm ProductA1" << endl;
	}
};

class ProductA2 : public ProductA
{
public:
	void Show() {
		cout << "I'm ProductA2" << endl;
	}
};

// Product B
class ProductB {
public:
	virtual void Show() = 0;
};

class ProductB1 : public ProductB
{
public:
	void Show() {
		cout << "I'm ProductB1" << endl;
	}
};

class ProductB2 : public ProductB
{
public:
	void Show() {
		cout << "I'm ProductB2" << endl;
	}
};

// Factory
class Factory {
public:
	virtual ProductA *CreateProductA() = 0;
	virtual ProductB *CreateProductB() = 0;
};

class Factory1 : public Factory
{
public:
	ProductA *CreateProductA() {
		return new ProductA1();
	}

	ProductB *CreateProductB() {
		return new ProductB1();
	}
};

class Factory2 : public Factory
{
	ProductA *CreateProductA() {
		return new ProductA2();
	}

	ProductB *CreateProductB() {
		return new ProductB2();
	}
};
複製代碼
#include<memory>
#include"AbstractFactoryPattern.h"

int main() {
	std::unique_ptr<Factory> facObj1(new Factory1);
	std::unique_ptr<ProductA> proObjA1(facObj1->CreateProductA());
	std::unique_ptr<ProductB> proObjB1(facObj1->CreateProductB());
	proObjA1->Show();
	proObjB1->Show();

	std::unique_ptr<Factory> facObj2(new Factory2);
	std::unique_ptr<ProductA> proObjA2(facObj2->CreateProductA());
	std::unique_ptr<ProductB> proObjB2(facObj2->CreateProductB());
	proObjA2->Show();
	proObjB2->Show();

    return 0;
}
複製代碼
相關文章
相關標籤/搜索