C++面試 設計模式之工廠模式
簡單工廠模式
在建立一個物件時不向客戶暴露內部細節;
簡單工廠不是設計模式,更像是一種程式設計習慣。它把例項化的操作單獨放到一個類中,這個類就成為簡單工廠類,讓簡單工廠類來決定應該用哪個子類來例項化。
假設有一個工廠,他能生產出A、B兩種產品。當客戶需要產品的時候,要告訴工廠是哪種產品,是A還是B。當新增加一種新產品的時候,那麼就要去修改工廠的類。
// Factory.cpp : 定義控制檯應用程式的入口點。
#include<iostream>
using namespace std;
class Product
{
public:
virtual void show() = 0;
};
class Product_A : public Product
{
public:
void show()
{
cout << "Product_A" << endl;
}
};
class Product_B : public Product
{
public:
void show()
{
cout << "Product_B" << endl;
}
};
class Factory
{
public:
Product* Create (int i)
{
switch (i)
{
case 1:
return new Product_A;
break;
case 2:
return new Product_B;
break;
default:
break;
}
}
};
int main()
{
Factory *factory = new Factory();
factory->Create(1 )->show();
factory->Create(2)->show();
system("pause");
return 0;
}
常用的場景
例如部署多種資料庫的情況,可能在不同的地方要使用不同的資料庫,此時只需要在配置檔案中設定資料庫的型別,每次再根據型別生成例項,這樣,不管下面的資料庫型別怎麼變化,在客戶端看來都是隻有一個AbstractProduct,使用的時候根本無需修改程式碼。提供的型別也可以用比較便於識別的字串,這樣不用記很長的類名,還可以儲存為配置檔案。
這樣,每次只需要修改配置檔案和新增新的產品子類即可。
所以簡單工廠模式一般應用於多種同類型類的情況,將這些類隱藏起來,再提供統一的介面,便於維護和修改。
優點
1.隱藏了物件建立的細節,將產品的例項化推遲到子類中實現。
2.客戶端基本不用關心使用的是哪個產品,只需要知道用哪個工廠就行了,提供的型別也可以用比較便於識別的字串。
3.方便新增新的產品子類,每次只需要修改工廠類傳遞的型別值就行了。
4.遵循了依賴倒轉原則。
缺點
1.要求產品子類的型別差不多,使用的方法名都相同,如果類比較多,而所有的類又必須要新增一種方法,則會是非常麻煩的事情。或者是一種類另一種類有幾種方法不相同,客戶端無法知道是哪一個產品子類,也就無法呼叫這幾個不相同的方法。
2.每新增一個產品子類,都必須在工廠類中新增一個判斷分支,這違背了開放-封閉原則。
工廠模式
上面的簡單工廠模式的缺點是當新增產品的時候就要去修改工廠的類,這就違反了開放封閉原則,(類、模組、函式)可以擴充套件,但是不可以修改,於是,就出現了工廠方法模式。所謂工廠方法模式,是指定義一個用於建立物件的介面,讓子類決定例項化哪一個類。
打個比方:
現在有A、B兩種產品,那麼久開兩個工廠。工廠A負責生產A產品,工廠B負責生產B種產品。這時候客戶不需要告訴工廠生產哪種產品了,只需要告訴工廠生產就可以了。
#include<iostream>
using namespace std;
class Product
{
public:
virtual void show() = 0;
};
class Product_A : public Product
{
public:
void show()
{
cout << "Product_A" << endl;
}
};
class Product_B : public Product
{
public:
void show()
{
cout << "Product_B" << endl;
}
};
class Factory
{
public:
virtual Product* create() = 0;
};
class Factory_A : public Factory
{
public:
Product* create()
{
return new Product_A;
}
};
class Factory_B : public Factory
{
public:
Product* create()
{
return new Product_B;
}
};
int main()
{
Factory_A* productA = new Factory_A();
Factory_B* productB = new Factory_B();
productA->create()->show();
productB->create()->show();
system("pause");
return 0;
}
常用的場景
基本與簡單工廠模式一致,只不過是改進了簡單工廠模式中的開放-封閉原則的缺陷,使得模式更具有彈性。將例項化的過程推遲到子類中,由子類來決定例項化哪個。
優點
基本與簡單工廠模式一致,多的一點優點就是遵循了開放-封閉原則,使得模式的靈活性更強。
缺點
與簡單工廠模式差不多。如果產品數量足夠多,要維護的量就會增加,好在一般工廠子類只用來生成產品類,只要產品子類的名稱不發生變化,那麼基本工廠子類就不需要修改,每次只需要修改產品子類就可以了。
抽象工廠模式
抽象工廠模式就變得比工廠模式更為複雜,就像上面提到的缺點一樣,工廠模式和簡單工廠模式要求產品子類必須要是同一型別的,擁有共同的方法,這就限制了產品子類的擴充套件。於是為了更加方便的擴充套件,抽象工廠模式就將同一類的產品子類歸為一類,讓他們繼承同一個抽象子類,我們可以把他們一起視作一組,然後好幾組產品構成一族。
為什麼要有抽象工廠模式?
假如我們A產品中有A1和A2兩種型號的廠品,B產品中有B1和B2兩種型號的廠品,那怎麼辦,上面兩種工廠模式就不能解決了。這個時候抽象工廠模式就登場了。還是開設兩家工廠,工廠A負責生產A1 、A2型號產品,B工廠負責生產B1、B2型號的產品。
提供一個建立一系列相關或相互依賴物件的介面,而無需指定它們具體的類。 適用性:一個系統要獨立於它的產品的建立、組合和表示時。一個系統要由多個產品系列中的一個來配置時。當你要強調一系列相關的產品物件的設計以便進行聯合使用時。當你提供一個產品類庫,而只想顯示它們的介面而不是實現時。
#include <iostream>
using namespace std;
//定義抽象類
class product1
{
public:
virtual void show() = 0;
};
//定義具體類
class product_A1 :public product1
{
public:
void show(){ cout << "product A1" << endl; }
};
class product_B1 :public product1
{
public:
void show(){ cout << "product B1" << endl; }
};
//定義抽象類
class product2
{
public:
virtual void show() = 0;
};
//定義具體類
class product_A2 :public product2
{
public:
void show(){ cout << "product A2" << endl; }
};
class product_B2 :public product2
{
public:
void show(){ cout << "product B2" << endl; }
};
class Factory
{
public:
virtual product1 *creat1() = 0;
virtual product2 *creat2() = 0;
};
class FactoryA
{
public:
product1 *creat1(){ return new product_A1(); }
product2 *creat2(){ return new product_A2(); }
};
class FactoryB
{
public:
product1 *creat1(){ return new product_B1(); }
product2 *creat2(){ return new product_B2(); }
};
int main()
{
FactoryA *factoryA = new FactoryA();
factoryA->creat1()->show();
factoryA->creat2()->show();
FactoryB *factoryB = new FactoryB();
factoryB->creat1()->show();
factoryB->creat2()->show();
return 0;
}
常用的場景
例如Linux和windows兩種作業系統下,有2個掛件A和B,他們在Linux和Windows下面的實現方式不同,Factory1負責產生能在Linux下執行的掛件A和B,Factory2負責產生能在Windows下執行的掛件A和B,這樣如果系統環境發生變化了,我們只需要修改工廠就行了。
優點
1.封裝了產品的建立,使得不需要知道具體是哪種產品,只需要知道是哪個工廠就行了。
2.可以支援不同型別的產品,使得模式靈活性更強。
3.可以非常方便的使用一族中間的不同型別的產品。
缺點
1.結構太過臃腫,如果產品型別比較多,或者產品族類比較多,就會非常難於管理。
2.每次如果新增一組產品,那麼所有的工廠類都必須新增一個方法,這樣違背了開放-封閉原則。所以一般適用於產品組合產品族變化不大的情況。