今天我學習了一下簡單工廠模式,其實簡單工廠模式並不被包含於GoF 23種設計模式中,但也是會被頻繁的使用在開發中,而且也算是其它工廠模式學習的入門吧。
首先,我想通過一個例子,引入今天的主題。如果我要設計一個學校職工信息管理系統,我要向服務器請求老師、學生、和其他工作人員的基本信息,那我們應該會如何進行設計呢?在不瞭解各種面向對象設計模式的時候,我們很容易想到的一種方法就是,先定義三個類分別是Student類、Teacher類、Other類,這三個類中分別存放了不同的對應相應類的屬性。然後定義一個People類用來繼承前面定義的三個類,並在其中加入一個classType來幫助返回我要請求的類中的數據。於是我們很容易寫出瞭如下代碼:
class People: public Student,public Teacher,public Other
{
private:
string type;
public:
People(string myType)
{
this->type = myType;
switch(this->type)
{
case "Student":{
//初始化學生信息
}break;
case "Teacher":{
//初始化教師信息
}break;
case "Other":{
//初始化其他員工信息
}break;
default:break;
}
}
void display()
{
if(this->type == "Student")
{
//輸出學生信息
}
else if(this->type == "Teacher")
{
//輸出教師信息
}
else if(this->type == "Other")
{
//輸出其他員工信息
}
}
}
毫無疑問,這個類是可以達到我們所需要達到的目的的,但是我們對照面向對象的設計原則,我們還是發現了許多問題:
1、People類的職責太重了,同時要完成所有的初始化和打印兩方面功能,違反了單一職責原則。
2、如果我今後要擴充功能,加入行政人員的資料查詢,那麼我還將要重新修改代碼,將類中的if/else判斷再加上一句,增加了添加模塊的難度,違反了開閉原則。
3、客戶只能用new關鍵字來創建對象,類和客戶端的耦合程度太高。
OK!那就上面三點,我們可以使用簡單工廠模式進行怎樣的改進呢?
首先,我們要了解,簡單工廠模式中的三個角色:
(1)工廠角色:這是該模式的核心部分,負責創建所有產品(對象),同時工廠可以被外界直接調用,創建所需產品的對象。
(2)抽象產品角色:工廠類所創建所有產品(對象)的父類,封裝了所有產品的公有方法,用於提高系統的靈活性。
(3)具體產品角色:該模式的創建目標,由他創建對象都是某個具體類的實例(ps:結合上面的例子,就可以理解爲Student類、Teacher類、Other類,他們都包含自己特有的屬性)
那麼,接下來我們就要開始實現了!!
第一步是抽象產品角色,我們要實現的功能是打印功能,因此,我們就需要一個只有display()功能的類,記住要是一個虛基類,因爲作爲一個接口類,我不需要在類中實現功能。
第二步要開始寫我們的具體產品角色了,每個類中的屬性有所不同,但是要記住的是:一定要公有繼承,抽象產品類,並在自己類中寫display()函數。
第三步,也是最重要的一步,我們要在工廠類中,做出邏輯判斷,寫一個靜態函數,通過傳進的參數來判斷是要請求哪種產品(即Student\Teacher\Other)的參數。
下面給出我寫的一個模板的代碼(我並沒有實現我之前舉得例子,因爲我學的時候,並沒有用這個例子寫代碼)
/*
* class.h
*
* Created on: 2014-3-20
* Author: linux
*/
#ifndef CLASS_H_
#define CLASS_H_
#include <iostream>
class DisplayInterface
{
public:
virtual void Display(){
};
};
class ClassA :public DisplayInterface
{
public:
ClassA(){
std::cout<<"create class A"<<std::endl;
}
~ClassA(){
}
virtual void Display();
};
class ClassB :public DisplayInterface
{
public:
ClassB(){
std::cout<<"create class B"<<std::endl;
}
~ClassB(){
}
virtual void Display();
};
class ClassC :public DisplayInterface
{
public:
ClassC(){
std::cout<<"create class C"<<std::endl;
}
~ClassC(){
}
virtual void Display();
};
void ClassA::Display(){
std::cout<<"display class A"<<std::endl;
}
void ClassB::Display(){
std::cout<<"display class B"<<std::endl;
}
void ClassC::Display(){
std::cout<<"display class C"<<std::endl;
}
class SimpleFactory
{
public:
static DisplayInterface* getClass(int type) {
DisplayInterface* classPtr = nullptr;
switch(type)
{
case 1:classPtr = new ClassA;break;
case 2:classPtr = new ClassB;break;
case 3:classPtr = new ClassC;break;
}
return classPtr;
}
};
#endif /* CLASS_H_ */
主函數的代碼如下
#include <iostream>
#include "class.h"
using namespace std;
int main()
{
DisplayInterface* ptr = SimpleFactory::getClass(1);
ptr->Display();
ptr = SimpleFactory::getClass(2);
ptr->Display();
ptr = SimpleFactory::getClass(3);
ptr->Display();
}
當然簡單工廠模式還是可以簡化的,就是將抽象產品角色和工廠合併帶一個類中。這個讀者自己可以嘗試一下。
最後介紹的是適用場景:
1、工廠類創建的對象比較少,以免工廠類太過於繁瑣
2、客戶端只需要知道往工廠傳入參數,而並不需要關心對象時如何創建的。