1. 程式人生 > >以C/C++語法淺談二十三種設計模式(一)——工廠模式(Factory Method)

以C/C++語法淺談二十三種設計模式(一)——工廠模式(Factory Method)

0.寫在前面

在軟體開發過程中,為了提高開發效率、增強軟體執行的穩定性,降低後期專案維護的成本,我們志在追求更加高效、簡單的設計思路來引領我們的專案產品,在經過不斷的探索與總結的過程中,我們最常用的設計模式有23中,總體分為三大類,即建立型模式、結構型模式和行為型模式,具體如下:

模式分類 具體模式
建立型模式 工廠方法模式、抽象工廠模式、單例模式、建造者模式、原型模式
結構型模式 介面卡模式、裝飾器模式、代理模式、外觀模式、橋接模式、組合模式、享元模式
行為型模式 策略模式、模板方法模式、觀察者模式、迭代子模式、責任鏈模式、命令模式、備忘錄模式、狀態模式、訪問者模式、中介者模式、直譯器模式

本篇以最常用的工廠模式進行講起,工廠模式主要包含靜態工廠模式(又叫靜態工廠模式)、工廠方法模式和抽象工廠模式三類。

一.靜態工廠模式(簡單工廠模式)

1. 簡單介紹

靜態工廠模式是工廠模式中最簡單的一種,它可以用比較簡單的方式隱藏建立物件的細節,一般只需要告訴工廠類所需要建立的型別,工廠類就會返回需要的類物件,而客戶端看到的也只是類的抽象物件(interface),因此無需關心到底是返回了哪個子類。
2.組成


靜態工廠模式由工廠類物件、抽象產品類物件、具體產品類物件組成。
1)工廠類物件:這是本模式的核心,含有一定的判斷邏輯,根據邏輯和需求的不同,產生具體的產品角色;
2)抽象產品類物件:它是具體產品的父類或者基類,提供具體實現的介面和方法;
3)具體產品類物件:它是抽象產品類物件派生出來的具體產品物件,對抽象產品類物件的介面方法進行例項化,實現自有的方法。

想象一下,現在的你是一家大型公司的老董,你公司旗下在全國各地都有自己的分公司,反正你是老總,年底了你最關心的是各家分公司給你賺取了多少錢的利潤,至於具體是怎麼賺的可能是經理、或者員工該關心的事。而公司我們可以將其理解為掙錢的工廠
我們首先看下有關這個公司(工廠)的UML圖:
在這裡插入圖片描述

3. 例項程式碼
首先,我們定義一個公司基類,像這樣:

#include <iostream>
using namespace std;

class Company
{
public:
	Company(){}
	virtual~Company(){}
public:
	virtual const std::string GetMoney()const = 0;
};

然後各分公司繼承公司基類彙報自己的營業額,像這樣:

//北京分公司
class BeiJingCompany:public Company
{
public:
	virtual const std::string GetMoney()const
	{
		return "北京賺了一個億";
	}
};
//武漢分公司
class WuHanCompany:public Company
{
public:
	virtual const std::string GetMoney()const
	{
		return "武漢賺了五千萬";
	}
};
//廣州分公司
class GuangZhouCompany:public Company
{
public:
	virtual const std::string GetMoney()const
	{
		return "廣州賺了八千萬";
	}
};

然後我們定義我們的工廠類,像這樣:

enum COMPANYNAME{BEIJING,WUHAN,GUANGZHOU};
class CompanyFactory
{
public:
	Company* CreateCompany(COMPANYNAME companyName)
	{
		switch(companyName)
		{
		case BEIJING:
			{
                return new BeiJingCompany();
			}break;
		case WUHAN:
			{
				return new WuHanCompany();
			}break;
		case GUANGZHOU:
			{
				return new GuangZhouCompany();
			}break;
		default:break;
		}
	}
};

到了這一步,我們的董事長來了,他想知道每個分公司今年各賺了多少錢,於是像下面這樣:

int main(int argc, char *argv[])
{
	CompanyFactory* factoryCompany = new CompanyFactory();
	if(factoryCompany)
	{
		Company* beijingCompany = factoryCompany->CreateCompany(BEIJING);
		beijingCompany->GetMoney();

		Company* wuhanCompany = factoryCompany->CreateCompany(WUHAN);
		wuhanCompany->GetMoney();

		Company* guangzhouCompany = factoryCompany->CreateCompany(GUANGZHOU);
		guangzhouCompany->GetMoney();
	}
	delete factoryCompany;
	factoryCompany = NULL;
	return 0;
}

二.工廠方法模式

1. 引子
隨著公司越做越大,你的分公司在短短的幾年時間裡已經遍佈全國各地,最近還想擴充套件海外市場,每開設一家分公司,我們就要在工廠類裡新增新公司,這可累壞我們的工廠類,於是工廠方法模式就這樣登場了。
2. 組成
**工廠方法模式由抽象工廠類物件、具體工廠類物件、抽象產品類物件、具體產品類物件組成。
1)抽象工廠類物件: 這是工廠方法模式的核心,它與應用程式無關。是具體工廠類物件必須實現的介面或者必須繼承的父類(基類)。
2)具體工廠類物件:它含有和具體業務邏輯有關的程式碼。由應用程式呼叫以建立對應的具體產品的物件。
3)抽象產品類物件:它是具體產品繼承的父類或者是實現的介面。
4)具體產品類物件:具體工廠角色所建立的物件就是此角色的例項。
工廠方法模式UML圖如下:
**
在這裡插入圖片描述

3.例項程式碼
首先定義一個抽象工廠基類和一個抽象產品基類,像這樣:

//抽象公司基類
class CompanyBase
{
public:
	CompanyBase(){}
	virtual~CompanyBase(){}

	virtual const std::string GetMoney()const = 0;
};
//抽象工廠基類
class FactoryBase
{
public:
	FactoryBase(){}
	virtual ~FactoryBase(){}
	virtual const CompanyBase* CreateCompany() const = 0;
};

然後定義具體的工廠類和具體的產品類,像這樣:

//北京產品例項化
class BeiJingCompany:public CompanyBase
{
public:
	virtual const std::string GetMoney()const
	{
		return "北京賺了一個億";
	}
};
//北京工廠例項化類
class BeiJingFactory:public FactoryBase
{
public:

  virtual const CompanyBase* CreateCompany() const
  {
	  return new BeiJingCompany();
  }
};
//武漢產品具體實現類
class WuHanCompany:public CompanyBase
{
public:
	virtual const std::string GetMoney()const
	{
		return "武漢賺了五千萬";
	}
};
//武漢工廠具體實現類
class WuHanFactory:public FactoryBase
{
public:

	virtual const CompanyBase* CreateCompany() const
	{
		return new WuHanCompany();
	}
};
//廣州產品具體實現類
class GuangZhouCompany:public CompanyBase
{
public:
	virtual const std::string GetMoney()const
	{
		return "廣州賺了八千萬";
	}
};
//廣州工廠具體實現類
class GuangZhouFactory:public FactoryBase
{
public:

	virtual const CompanyBase* CreateCompany() const
	{
		return new GuangZhouCompany();
	}
};

好了到我們的大Boss董事長登場了

int main(int argc, char *argv[])
{
	FactoryBase* factoryBeijing = new BeiJingFactory();
	CompanyBase* beijingCompany = factoryBeijing->CreateCompany();
	beijingCompany->GetMoney();

	FactoryBase* factoryWuhan = new WuHanFactory();
	CompanyBase* wuhanCompany = factoryWuhan->CreateCompany();
	wuhanCompany->GetMoney();

	FactoryBase* guangzhouWuhan = new GuangZhouFactory();
	CompanyBase* guangzhouCompany = guangzhouWuhan->CreateCompany();
	guangzhouCompany->GetMoney();
	return 0;
}

可以看出,每個工廠只生產某一種產品,不同的工廠生產不同的產品,而具體該生產哪一種產品的邏輯交給客戶端這邊進行處理。

三.抽象工廠模式

1.引子
隨著公司不斷髮展壯大,單一的業務已經不能滿足日益發展的社會,我們準備開展公司的第二業務路線,在各地分公司進行實行,為了適應後續隨著公司的不斷髮展可能增加的更多的業務路線,我們引出了抽象工廠模式
2. 組成
抽象工廠模式的組合和工廠方法模式的組合一樣,也是由抽象工廠類物件、具體工廠類物件、抽象產品類物件、具體產品類物件組成。

3.例項程式碼
由於現在我們增加了第二業務路線,我們首先定義兩個業務的基類,如下:

//第一業務基類
class ProductBaseOne
{
public:
	ProductBaseOne(){}
	virtual ~ProductBaseOne(){}
public:
	virtual std::string GetMoney() = 0;
};
//第二業務基類
class ProductBaseTwo
{
public:
	ProductBaseTwo(){}
	virtual ~ProductBaseTwo(){}
public:
	virtual std::string GetMoney() = 0;
};

然後定義各個分公司的業務類,實現介面方法,如下所示:

//北京第一業務營業額
class BeiJingCompanyOne:public ProductBaseOne
{
public:
	virtual std::string GetMoney() 
	{
       return "北京第一業務賺了一個億";
	}
};
//北京第二業務營業額
class BeiJingCompanyTwo:public ProductBaseTwo
{
public:
	virtual std::string GetMoney() 
	{
		return "北京第二業務賺了八千萬";
	}
};

//武漢第一業務營業額
class WuhanCompanyOne:public ProductBaseOne
{
public:
	virtual std::string GetMoney() 
	{
		return "武漢第一業務賺了一個億";
	}
};

//武漢第二業務營業額
class WuhanCompanyTwo:public ProductBaseTwo
{
public:
	virtual std::string GetMoney() 
	{
		return "武漢第二業務賺了一個億";
	}
};

//廣州第一業務營業額
class GuangzhouCompanyOne:public ProductBaseOne
{
public:
	virtual std::string GetMoney() 
	{
		return "廣州第一業務賺了一個億";
	}
};

//廣州第二業務營業額
class GuangzhouCompanyTwo:public ProductBaseTwo
{
public:
	virtual std::string GetMoney() 
	{
		return "廣州第二業務賺了五千萬";
	}
};

接著定義一個工廠介面,分別建立第一、第二業務類物件

//工廠介面父類(基類)
class FactoryProductBase
{
public:
	FactoryProductBase(){}
	virtual~FactoryProductBase(){}

public:
	virtual ProductBaseOne* CreateProductOne() = 0;    //生成第一業務物件

	virtual ProductBaseOne* CreateProductTwo() = 0;    //生成第二業務物件
};

class BeijingCompanyFactory:public FactoryProductBase
{
public:
	virtual ProductBaseOne* CreateProductOne()
	{
		return new BeiJingCompanyOne();
	}

	virtual ProductBaseTwo* CreateProductTwo()
	{
		return new BeiJingCompanyTwo();
	}
};

class WuhanCompanyFactory:public FactoryProductBase
{
public:
	virtual ProductBaseOne* CreateProductOne()
	{
		return new WuhanCompanyOne();
	}

	virtual ProductBaseTwo* CreateProductTwo()
	{
		return new WuhanCompanyTwo();
	}
};

class GuangzhouCompanyFactory:public FactoryProductBase
{
public:
	virtual ProductBaseOne* CreateProductOne()
	{
		return new GuangzhouCompanyOne();
	}

	virtual ProductBaseTwo* CreateProductTwo()
	{
		return new GuangzhouCompanyTwo();
	}
};

最後,在我們的高階邏輯模組可按如下方法進行呼叫:

int main(int argc, char *argv[])
{
	FactoryProductBase* beijingCompany = new BeijingCompanyFactory();
	ProductBaseOne* beijingProductOne = beijingCompany->CreateProductOne();
	ProductBaseTwo* beijingProducttwo = beijingCompany->CreateProductTwo();
	beijingProductOne->GetMoney();
	beijingProducttwo->GetMoney();

	FactoryProductBase* wuhanCompany = new WuhanCompanyFactory();
	ProductBaseOne* wuhanProductOne = wuhanCompany->CreateProductOne();
	ProductBaseTwo* wuhanProducttwo = wuhanCompany->CreateProductTwo();
	wuhanProductOne->GetMoney();
	wuhanProducttwo->GetMoney();

	FactoryProductBase* guangzhouCompany = new GuangzhouCompanyFactory();
	ProductBaseOne* guangzhouProductOne = guangzhouCompany->CreateProductOne();
	ProductBaseTwo* guangzhouProducttwo = guangzhouCompany->CreateProductTwo();
	guangzhouProductOne->GetMoney();
	guangzhouProducttwo->GetMoney();
	
	return 0;
}

從上可以看出,之所以叫抽象工廠,是因為跟工廠方法相比,這裡會存在多個抽象產品類(第一業務產品和第二產品業務)而工廠介面有多個方法,用來產生出不同的抽象產品。

四.總結

準確來說,簡單工廠模式不屬於常用的設計模式之一,因為它違背了六大設計原則之一的開閉原則(後期會專門針對開閉設計原則進行總結)。簡單工廠模式適用於需要建立的物件比較少的情況,高層模組通過傳參就可獲取獲取到自己想要的物件。
工廠方法模式主要針對單一產品結構的情況,當產品模組增多或者邏輯變得複雜的時候使用工廠方法模式就需要改動很多的程式碼,增加不必要的冗餘。
抽象工廠模式則是針對多級產品結構(系列產品)的一種工廠模式。它將產品的方法和實現相分離,降低了程式碼之間的耦合性,方便專案的後期維護。在增減新物件時只需要新增新工廠方法就可以實現,無需改動大量的程式碼。