初識工廠模式 我們先看工廠模式的介紹 這種類型的設計模式屬於創建型模式,它提供了一種創建對象的最佳方式。 在工廠模式中,我們在創建對象時不會對客戶端暴露創建邏輯,並且是通過使用一個共同的介面來指向新創建的對象。 簡單來說,使用了C++ 多態 的特性,將存在 繼承 關係的類,通過一個 工廠類創建 對應 ...
初識工廠模式
我們先看工廠模式的介紹
這種類型的設計模式屬於創建型模式,它提供了一種創建對象的最佳方式。
在工廠模式中,我們在創建對象時不會對客戶端暴露創建邏輯,並且是通過使用一個共同的介面來指向新創建的對象。
簡單來說,使用了C++多態的特性,將存在繼承關係的類,通過一個工廠類創建對應的子類(派生類)對象。在項目複雜的情況下,可以便於子類對象的創建。
工廠模式的實現方式可分別簡單工廠模式、工廠方法模式、抽象工廠模式,每個實現方式都存在優和劣。
最近炒鞋炒的非常的火,那麼以鞋廠的形式,一一分析針對每個實現方式進行分析。
簡單工廠模式
具體的情形:
- 鞋廠可以指定生產耐克、阿迪達斯和李寧牌子的鞋子。哪個鞋炒的火爆,老闆就生產哪個,看形勢生產。
UML圖:
簡單工廠模式的結構組成:
- 工廠類(
ShoesFactory
):工廠模式的核心類,會定義一個用於創建指定的具體實例對象的介面。 - 抽象產品類(
Shoes
):是具體產品類的繼承的父類或實現的介面。 - 具體產品類(
NiKeShoes\AdidasShoes\LiNingShoes
):工廠類所創建的對象就是此具體產品實例。
簡單工廠模式的特點:
- 工廠類封裝了創建具體產品對象的函數。
簡單工廠模式的缺陷:
- 擴展性非常差,新增產品的時候,需要去修改工廠類。
簡單工廠模式的代碼:
Shoes
為鞋子的抽象類(基類),介面函數為Show()
,用於顯示鞋子廣告。NiKeShoes
、AdidasShoes
、LiNingShoes
為具體鞋子的類,分別是耐克、阿迪達斯和李寧鞋牌的鞋,它們都繼承於Shoes
抽象類。
// 鞋子抽象類
class Shoes
{
public:
virtual ~Shoes() {}
virtual void Show() = 0;
};
// 耐克鞋子
class NiKeShoes : public Shoes
{
public:
void Show()
{
std::cout << "我是耐克球鞋,我的廣告語:Just do it" << std::endl;
}
};
// 阿迪達斯鞋子
class AdidasShoes : public Shoes
{
public:
void Show()
{
std::cout << "我是阿迪達斯球鞋,我的廣告語:Impossible is nothing" << std::endl;
}
};
// 李寧鞋子
class LiNingShoes : public Shoes
{
public:
void Show()
{
std::cout << "我是李寧球鞋,我的廣告語:Everything is possible" << std::endl;
}
};
ShoesFactory
為工廠類,類里實現根據鞋子類型創建對應鞋子產品對象的CreateShoes(SHOES_TYPE type)
函數。
enum SHOES_TYPE
{
NIKE,
LINING,
ADIDAS
};
// 總鞋廠
class ShoesFactory
{
public:
// 根據鞋子類型創建對應的鞋子對象
Shoes *CreateShoes(SHOES_TYPE type)
{
switch (type)
{
case NIKE:
return new NiKeShoes();
break;
case LINING:
return new LiNingShoes();
break;
case ADIDAS:
return new AdidasShoes();
break;
default:
return NULL;
break;
}
}
};
main
函數,先是構造了工廠對象,後創建指定類型的具體鞋子產品對象,創建了具體鞋子產品的對象便可直接列印廣告。因為採用的是new
的方式創建了對象,用完了要通過delete
釋放資源資源哦!
int main()
{
// 構造工廠對象
ShoesFactory shoesFactory;
// 從鞋工廠對象創建阿迪達斯鞋對象
Shoes *pNikeShoes = shoesFactory.CreateShoes(NIKE);
if (pNikeShoes != NULL)
{
// 耐克球鞋廣告喊起
pNikeShoes->Show();
// 釋放資源
delete pNikeShoes;
pNikeShoes = NULL;
}
// 從鞋工廠對象創建阿迪達斯鞋對象
Shoes *pLiNingShoes = shoesFactory.CreateShoes(LINING);
if (pLiNingShoes != NULL)
{
// 李寧球鞋廣告喊起
pLiNingShoes->Show();
// 釋放資源
delete pLiNingShoes;
pLiNingShoes = NULL;
}
// 從鞋工廠對象創建阿迪達斯鞋對象
Shoes *pAdidasShoes = shoesFactory.CreateShoes(ADIDAS);
if (pAdidasShoes != NULL)
{
// 阿迪達斯球鞋廣告喊起
pAdidasShoes->Show();
// 釋放資源
delete pAdidasShoes;
pAdidasShoes = NULL;
}
return 0;
}
- 輸出結果:
[root@lincoding factory]# ./simpleFactory
我是耐克球鞋,我的廣告語:Just do it
我是阿迪達斯球鞋,我的廣告語:Impossible is nothing
我是李寧球鞋,我的廣告語:Everything is possible
工廠方法模式
具體情形:
- 現各類鞋子抄的非常火熱,於是為了大量生產每種類型的鞋子,則要針對不同品牌的鞋子開設獨立的生產線,那麼每個生產線就只能生產同類型品牌的鞋。
UML圖:
工廠方法模式的結構組成:
- 抽象工廠類廠(
ShoesFactory
):工廠方法模式的核心類,提供創建具體產品的介面,由具體工廠類實現。 - 具體工廠類(
NiKeProducer\AdidasProducer\LiNingProducer
):繼承於抽象工廠,實現創建對應具體產品對象的方式。 - 抽象產品類(
Shoes
):它是具體產品繼承的父類(基類)。 - 具體產品類(
NiKeShoes\AdidasShoes\LiNingShoes
):具體工廠所創建的對象,就是此類。
工廠方法模式的特點:
- 工廠方法模式抽象出了工廠類,提供創建具體產品的介面,交由子類去實現。
- 工廠方法模式的應用並不只是為了封裝具體產品對象的創建,而是要把具體產品對象的創建放到具體工廠類實現。
工廠方法模式的缺陷:
- 每新增一個產品,就需要增加一個對應的產品的具體工廠類。相比簡單工廠模式而言,工廠方法模式需要更多的類定義。
- 一條生產線只能一個產品。
工廠方法模式的代碼:
ShoesFactory
抽象工廠類,提供了創建具體鞋子產品的純虛函數。NiKeProducer
、AdidasProducer
、LiNingProducer
具體工廠類,繼承持續工廠類,實現對應具體鞋子產品對象的創建。
// 總鞋廠
class ShoesFactory
{
public:
virtual Shoes *CreateShoes() = 0;
virtual ~ShoesFactory() {}
};
// 耐克生產者/生產鏈
class NiKeProducer : public ShoesFactory
{
public:
Shoes *CreateShoes()
{
return new NiKeShoes();
}
};
// 阿迪達斯生產者/生產鏈
class AdidasProducer : public ShoesFactory
{
public:
Shoes *CreateShoes()
{
return new AdidasShoes();
}
};
// 李寧生產者/生產鏈
class LiNingProducer : public ShoesFactory
{
public:
Shoes *CreateShoes()
{
return new LiNingShoes();
}
};
main
函數針對每種類型的鞋子,構造了每種類型的生產線,再由每個生產線生產出對應的鞋子。需註意的是具體工廠對象和具體產品對象,用完了需要通過delete
釋放資源。
int main()
{
// ================ 生產耐克流程 ==================== //
// 鞋廠開設耐克生產線
ShoesFactory *niKeProducer = new NiKeProducer();
// 耐克生產線產出球鞋
Shoes *nikeShoes = niKeProducer->CreateShoes();
// 耐克球鞋廣告喊起
nikeShoes->Show();
// 釋放資源
delete nikeShoes;
delete niKeProducer;
// ================ 生產阿迪達斯流程 ==================== //
// 鞋廠開設阿迪達斯生產者
ShoesFactory *adidasProducer = new AdidasProducer();
// 阿迪達斯生產線產出球鞋
Shoes *adidasShoes = adidasProducer->CreateShoes();
// 阿迪達斯球鞋廣喊起
adidasShoes->Show();
// 釋放資源
delete adidasShoes;
delete adidasProducer;
return 0;
}
- 輸出結果:
[root@lincoding factory]# ./methodFactory
我是耐克球鞋,我的廣告語:Just do it
我是阿迪達斯球鞋,我的廣告語:Impossible is nothing
抽象工廠模式
具體情形:
- 鞋廠為了擴大了業務,不僅只生產鞋子,把運動品牌的衣服也一起生產了。
UML圖:
抽象工廠模式的結構組成(和工廠方法模式一樣):
- 抽象工廠類廠(
ShoesFactory
):工廠方法模式的核心類,提供創建具體產品的介面,由具體工廠類實現。 - 具體工廠類(
NiKeProducer
):繼承於抽象工廠,實現創建對應具體產品對象的方式。 - 抽象產品類(
Shoes\Clothe
):它是具體產品繼承的父類(基類)。 - 具體產品類(
NiKeShoes\NiKeClothe
):具體工廠所創建的對象,就是此類。
抽象工廠模式的特點:
- 提供一個介面,可以創建多個產品族中的產品對象。如創建耐克工廠,則可以創建耐克鞋子產品、衣服產品、褲子產品等。
抽象工廠模式的缺陷:
- 同工廠方法模式一樣,新增產品時,都需要增加一個對應的產品的具體工廠類。
抽象工廠摸是的代碼:
Clothe
和Shoes
,分別為衣服和鞋子的抽象產品類。NiKeClothe
和NiKeShoes
,分別是耐克衣服和耐克衣服的具體產品類。
// 基類 衣服
class Clothe
{
public:
virtual void Show() = 0;
virtual ~Clothe() {}
};
// 耐克衣服
class NiKeClothe : public Clothe
{
public:
void Show()
{
std::cout << "我是耐克衣服,時尚我最在行!" << std::endl;
}
};
// 基類 鞋子
class Shoes
{
public:
virtual void Show() = 0;
virtual ~Shoes() {}
};
// 耐克鞋子
class NiKeShoes : public Shoes
{
public:
void Show()
{
std::cout << "我是耐克球鞋,讓你酷起來!" << std::endl;
}
};
Factory
為抽象工廠,提供了創建鞋子CreateShoes()
和衣服產品CreateClothe()
對象的介面。NiKeProducer
為具體工廠,實現了創建耐克鞋子和耐克衣服的方式。
// 總廠
class Factory
{
public:
virtual Shoes *CreateShoes() = 0;
virtual Clothe *CreateClothe() = 0;
virtual ~Factory() {}
};
// 耐克生產者/生產鏈
class NiKeProducer : public Factory
{
public:
Shoes *CreateShoes()
{
return new NiKeShoes();
}
Clothe *CreateClothe()
{
return new NiKeClothe();
}
};
main
函數,構造耐克工廠對象,通過耐克工廠對象再創建耐克產品族的衣服和鞋子對象。同樣,對象不再使用時,需要手動釋放資源。
int main()
{
// ================ 生產耐克流程 ==================== //
// 鞋廠開設耐克生產線
Factory *niKeProducer = new NiKeProducer();
// 耐克生產線產出球鞋
Shoes *nikeShoes = niKeProducer->CreateShoes();
// 耐克生產線產出衣服
Clothe *nikeClothe = niKeProducer->CreateClothe();
// 耐克球鞋廣告喊起
nikeShoes->Show();
// 耐克衣服廣告喊起
nikeClothe->Show();
// 釋放資源
delete nikeShoes;
delete nikeClothe;
delete niKeProducer;
return 0;
}
- 輸出結果:
[root@lincoding factory]# ./abstractFactory
我是耐克球鞋,讓你酷起來!
我是耐克衣服,時尚我最在行!
總結
以上三種工廠模式,在新增產品時,都存在一定的缺陷。
- 簡單工廠模式,,需要去修改工廠類,這違背了開閉法則。
- 工廠方式模式和抽象工廠模式,都需要增加一個對應的產品的具體工廠類,這就會增大了代碼的編寫量。
那麼有什麼好的方法,在新增產品時,即不用修改工廠類,也不用新增具體的工廠類?
筆者在實際項目中看到一個封裝性非常強的工廠類,在擴展新產品時,不需要修改工廠類,也不需要新增具體的工廠類,詳細內容可以跳轉至C++ 深入淺出工廠模式(進階篇)閱讀。