序
書上是三個(gè)模式——簡單工廠模式、工廠模式妈经、抽象工廠模式淮野,一塊說。對(duì)于昨天實(shí)在沒有休息好的狀態(tài)下吹泡,看到如此混亂的景象骤星,確實(shí)有點(diǎn)受不了。好在后面一遍又一遍重復(fù)爆哑,總算是理解了洞难。但是,既然是記筆記揭朝,也是給別人看队贱,那么我覺得拆開來說或許更加明白。
1潭袱、背景
書上用pizza來打比方柱嫌,其實(shí)還是挺愛吃,但是名字太繞口屯换,而且也不熟悉编丘。所以還是用餃子我覺得會(huì)更加親切些——我最愛吃的。
現(xiàn)在我要開一家餃子館,供應(yīng)各種口味的餃子瘪吏,三鮮餡癣防,胡蘿卜羊肉餡,西胡蝦仁餡掌眠,芹菜牛肉餡蕾盯,豬肉大蔥餡,豬肉白菜餡——看來好吃的說起來都沒完沒了蓝丙。
最開始的想法是级遭,按照如下步驟建立餃子:
1)用餃子抽象類建立餃子對(duì)象實(shí)體。
2)包餃子渺尘。
3)煮餃子挫鸽。
4)裝盤,配醬油和醋鸥跟。
5)上桌或打包外賣丢郊。
實(shí)現(xiàn)成的代碼如下——為了不讓很多的名詞困擾,此處直接采用更加形式化的命名方法:
//產(chǎn)品類型
abstract class ProductBase
{
@Override
public String toString() {
return "productbase";
}
}
class Product1 extends ProductBase
{
@Override
public String toString() {
return "product1";
}
}
class Product2 extends ProductBase
{
@Override
public String toString() {
return "product2";
}
}
//商店
class Store
{
ProductBase product;
public void create(String product) {
if(product.equals("product1"))
this.product=new Product1();
else if(product.equals("product2"))
this.product=new Product2();
//后續(xù)的操作
//包餃子();
//煮餃子()医咨;
//裝盤枫匾,配醬油和醋();
//上桌或打包()拟淮;
}
}
上面的代碼將創(chuàng)建餃子對(duì)象和對(duì)餃子的后續(xù)的加工操作干茉,嚴(yán)重耦合,造成以下兩個(gè)比較嚴(yán)重的問題:
1)一個(gè)函數(shù)中的代碼量過大很泊,而且隨著新類型產(chǎn)品研發(fā)角虫,這個(gè)函數(shù)將越來越大,不容易維護(hù)委造。
2)當(dāng)餐館發(fā)明新的餃子時(shí)戳鹅,就需要修改sell()方法。原來類的封裝性就遭到破壞争涌。
2粉楚、簡單工廠模式
根據(jù)上面的問題,我們自然想到的是將創(chuàng)建產(chǎn)品對(duì)象的那部分代碼進(jìn)行封裝亮垫,這樣就實(shí)現(xiàn)了工廠模式。簡單工廠模式如下:
//產(chǎn)品類型
abstract class ProductBase
{
@Override
public String toString() {
return "productbase";
}
}
class Product1 extends ProductBase
{
@Override
public String toString() {
return "product1";
}
}
class Product2 extends ProductBase
{
@Override
public String toString() {
return "product2";
}
}
class ProductFactory
{
public ProductBase create(String product)
{
if(product.equals("product1"))
return new Product1();
else if(product.equals("product2"))
return new Product2();
else return null;
}
}
//商店
class Store
{
ProductBase product;
ProductFactory productFactory;
public Store(ProductFactory productFactory)
{
this.productFactory=productFactory;
}
public void create(String product) {
/* if(product.equals("product1"))
this.product=new Product1();
else if(product.equals("product2"))
this.product=new Product2();
*/
this.productFactory.create(product);
//后續(xù)的操作
//包餃子();
//煮餃子()伟骨;
//裝盤饮潦,配醬油和醋();
//上桌或打包()携狭;
}
}
“簡單工廠模式”是將對(duì)象的生成和使用進(jìn)行分離继蜡,以組合的方式,當(dāng)創(chuàng)建使用某一類對(duì)象的實(shí)體時(shí)(如Store類的對(duì)象),將真正創(chuàng)建對(duì)象的工廠傳入稀并。從而獲得以下兩方面的收益:
1)工廠可以在動(dòng)態(tài)運(yùn)行時(shí)的時(shí)候指定仅颇。比如我現(xiàn)在不打算開餃子店了,想做包子碘举,由于包子和餃子的后續(xù)工作都是一樣的忘瓦,所以只需把制作包子的工廠傳入Store類中就行。
2)產(chǎn)品引颈、制作耕皮、使用三者進(jìn)行了有效分離。產(chǎn)品的分離已經(jīng)在前面的策略模式中說道——用抽象接口來“臨時(shí)”代替具體類蝙场,占位置凌停,將創(chuàng)建對(duì)象實(shí)體推遲到運(yùn)行時(shí)。制作即使用了簡單工廠模式售滤,而使用即為Store類罚拟。這樣就在一定程度上,將類之間的耦合度降到很低完箩。
3赐俗、工廠模式
相對(duì)于簡單工廠模式,工廠模式的耦合度相對(duì)來說比較大嗜憔。之所以比較大秃励,先看下面的例子。
假設(shè)餃子店生意不錯(cuò)吉捶,規(guī)模逐漸增大夺鲜,最后成立一個(gè)實(shí)業(yè)公司——餃子餐飲有限公司,而且設(shè)立了各個(gè)分部——華北子公司呐舔,東北子公司币励,華南子公司,華東子公司珊拼,中西部子公司食呻。為了保證所有公司生產(chǎn)的餃子質(zhì)量過關(guān),公司決定控制生產(chǎn)流程澎现。所有子公司可以根據(jù)當(dāng)?shù)靥禺a(chǎn)仅胞,選擇自己的餡料,但是制作工藝必須嚴(yán)格按照公司的流程剑辫,比如每個(gè)面皮必須為10g干旧,直徑5CM的圓面片。餡料必須20g妹蔽。
這樣椎眯,既增加了靈活性——子公司可以根據(jù)當(dāng)?shù)靥禺a(chǎn)選擇餡料挠将,又保證了質(zhì)量——嚴(yán)格按照母公司的規(guī)程辦事。
說這么多编整,我想“簡單工廠模式”和“工廠模式”應(yīng)用的場景大家也應(yīng)該能看出來了舔稀。
1)簡單工廠模式是針對(duì)只有一個(gè)使用者的情況來說,即程序中只有一個(gè)Store類掌测,這個(gè)Store類可以使用多用“工廠類”來為自己加工產(chǎn)品内贮。
2)工廠模式不同,它是針對(duì)某個(gè)基類的一堆子類赏半,在保證某些流程不改變的情況下贺归, 允許子類有自己的行為特征。也就是說断箫,基類規(guī)定了框架拂酣,而子類只能在框架的基礎(chǔ)上修補(bǔ)、更改仲义。
那么看下面的代碼就比較能說明問題了:
abstract class ProductBase
{
@Override
public String toString() {
return "productbase";
}
}
class a1 extends ProductBase
{
@Override
public String toString() {
return "a1";
}
}
class a2 extends ProductBase
{
@Override
public String toString() {
return "a2";
}
}
class b1 extends ProductBase
{
@Override
public String toString() {
return "b1";
}
}
class b2 extends ProductBase
{
@Override
public String toString() {
return "b2";
}
}
//創(chuàng)建工廠基類
abstract class FactoryBase
{
public abstract ProductBase create(String type);
final public ProductBase sell(String type)
{
ProductBase productBase;
productBase=create(type);
//后續(xù)的操作
//包餃子();
//煮餃子()婶熬;
//裝盤,配醬油和醋()埃撵;
//上桌或打包()赵颅;
return productBase;
}
}
//實(shí)現(xiàn)工廠派生類
class Factory1 extends FactoryBase
{
@Override
public ProductBase create(String type) {
ProductBase productBase=null;
if(type.equals("a1"))
productBase=new a1();
else if(type.equals("a2"))
productBase=new a2();
return productBase;
}
}
class Factory2 extends FactoryBase
{
@Override
public ProductBase create(String type) {
ProductBase productBase=null;
if(type.equals("b1"))
productBase=new b1();
else if(type.equals("b2"))
productBase=new b2();
return productBase;
}
}
如上代碼所示:
1)分別建立產(chǎn)品基類、工廠基類暂刘。由產(chǎn)品基類饺谬,根據(jù)不同地區(qū)(地區(qū)a和地區(qū)b),構(gòu)建了子類產(chǎn)品谣拣。相應(yīng)的募寨,也構(gòu)建了不同的子類工廠。
2)基類工廠中森缠,sell()方法作為對(duì)外統(tǒng)一方法拔鹰,控制生產(chǎn)總流程,因此生命為final方法贵涵。而create()方法則因地制宜列肢,按照不同地區(qū)特點(diǎn),生產(chǎn)特定的產(chǎn)品宾茂。
這樣瓷马,工廠方法既保證了修改的靈活性,也保證了某些必要操作不會(huì)被修改跨晴。