前言 模式介紹 簡單工廠模式其實並不屬於GoF23(23種設計模式),更類似工廠模式的一種變型。其定義是可以根據參數的不同返回不同類的實例。簡單工廠模式專門定義一個類來負責創建其他類的實例,被創建的實例通常都具有共同的父類。 這就有點像去飯館吃飯,進了門和服務員說一句:“waiter!來一份海參炒麵 ...
前言
模式介紹
簡單工廠模式其實並不屬於GoF23(23種設計模式),更類似工廠模式的一種變型。其定義是可以根據參數的不同返回不同類的實例。簡單工廠模式專門定義一個類來負責創建其他類的實例,被創建的實例通常都具有共同的父類。
這就有點像去飯館吃飯,進了門和服務員說一句:“waiter!來一份海參炒麵!” 一般情況下他只會給你海參炒麵(不管裡面有沒有海參)。這會第二個人進來了,也喊了一句:“服務員,來一碗辣根湯麵!”此時他就會給你一份辣根湯麵。你們根本不會考慮海參炒麵和辣根湯麵咋炒的,只需要告訴店家,他就給你了。
上面實例中的“服務員”就是一個簡單工廠。飯館里的菜單就是簡單工廠中的類列表。可以通過告知服務員點哪個類,服務員將類的實例也就是菜品端出來。這樣對於我這個這個客戶端來講,沒必要知道後廚做了什麼,只需要拿到實例菜品吃就好了。如果終於有一天海參炒麵變成了燒烤店,但是我也沒必要知道後廚咋串的串兒,只需要進去還找服務員,要腰子就OK了。
UML類圖
這裡涉及到2種類,①我:客戶端,負責調用服務員生成後端菜品實例。②服務員:工廠類,負責產生後端菜品並返回給客戶端。③菜品:後端菜品類,生成的菜品。具體關係如下UML類圖:
代碼實例
下麵是noodle類,是一個抽象類,裡面具備一個eating函數,是為客戶端準備的,食用。
#ifndef NOODLE_H
#define NOODLE_H
class noodle {
public:
noodle() {}
~noodle() {}
public:
virtual void eating() = 0;
};
#endif // NOODLE_H
下麵是海參炒麵類,集成自noodle類,實現了eating方法:
#ifndef HAISHENNOODLE_H
#define HAISHENNOODLE_H
#include "noodle.h"
class haishennoodle : public noodle
{
public:
haishennoodle();
~haishennoodle();
public:
virtual void eating();
};
#endif // HAISHENNOODLE_H
#include <iostream>
#include "haishennoodle.h"
haishennoodle::haishennoodle()
{
}
haishennoodle::~haishennoodle()
{
}
void haishennoodle::eating()
{
std::cout << "我是海參炒麵,裡面沒有海參哦!!吃的時候註意!" << std::endl;
}
下麵是辣根湯麵類,繼承了noodle類,重寫了eating方法:
#ifndef LAGENNOODLE_H
#define LAGENNOODLE_H
#include "noodle.h"
class lagennoodle : public noodle
{
public:
lagennoodle();
~lagennoodle();
public:
virtual void eating();
};
#endif // LAGENNOODLE_H
#include <iostream>
#include "lagennoodle.h"
lagennoodle::lagennoodle()
{
}
lagennoodle::~lagennoodle()
{
}
void lagennoodle::eating()
{
std::cout << "我是辣根湯麵,吃完嗆的哼啊!!!" << std::endl;
}
下麵是服務員類,負責生成後端noodle。通過createnoodle生成noodle實例化,是工廠。
#ifndef WAITER_H
#define WAITER_H
class noodle;
class waiter
{
public:
waiter();
~waiter();
public:
noodle *createnoodle(int type);
};
#endif // WAITER_H
#include <iostream>
#include "waiter.h"
#include "haishennoodle.h"
#include "lagennoodle.h"
waiter::waiter()
{
}
waiter::~waiter()
{
}
noodle *waiter::createnoodle(int type)
{
noodle *n = NULL;
switch(type) {
case 0:
n = new haishennoodle();
break;
case 1:
n = new lagennoodle();
break;
default:
std::cout << "對不起,我們這沒有這個菜,請您換一個!" << std::endl;
}
return n;
}
客戶端代碼如下,是我進店來點餐的步驟:
#include <iostream>
#include <string.h>
#include "haishennoodle.h"
#include "lagennoodle.h"
#include "waiter.h"
using namespace std;
char *product_list[] = {
"haishen-noodle",
"lagen-noodle",
NULL
};
int main()
{
char *p = NULL;
char *pd = "haishen-noodle";
int i = 0;
waiter *w = new waiter();
noodle *n = NULL;
for(p = product_list[i]; p != NULL; i++, p = product_list[i]) {
if(strncmp(pd, p, strlen(pd)) == 0) {
n = w->createnoodle(i);
if(n) {
cout << "開吃!!!" << endl;
n->eating();
}
}
}
if(n) {
delete n; n = NULL;
}
if(w) {
delete w; w = NULL;
}
return 0;
}
附贈CMakeList.txt代碼:
cmake_minimum_required(VERSION 2.8)
project(noodle)
set(SRC_LIST main.cpp noodle.h lagennoodle.h lagennoodle.cpp haishennoodle.h haishennoodle.cpp waiter.h waiter.cpp)
add_executable(${PROJECT_NAME} ${SRC_LIST})
編譯運行結果
代碼下載鏈接是:https://github.com/erguangqiang/freesir_headfirst/blob/master/noodle.tar.gz
使用cmake生成Makefile,並編譯出可執行程式noodle。運行結果如下:
erguangqiang@elab$./noodle
開吃!!!
我是海參炒麵,裡面沒有海參哦!!吃的時候註意!
結束
使用簡單工廠模式優點就是可以隔離客戶端和實例化,這樣客戶端可以不理會類實例化的具體流程,達到了給客戶端和邏輯解耦的目的。
但是簡單工廠模式缺點也很嚴重,根據設計模式的開放-封閉原則,對於程式的擴展,不應改變類具體代碼,可以對類集成擴展開放。一旦面館出了新菜品,就需要修改工廠類。規避的方法是使用工廠模式,通過擴展的方式來實現。