正如同筆者在<簡單工廠模式>一節裡介紹的
工廠模式有簡單工廠模式
工廠方法模式和抽象工廠模式幾種形態
簡單工廠模式已經在前面作過介紹
在簡單工廠模式中
一個工廠類處於對產品類實例化調用的中心位置上
它決定那一個產品類應當被實例化
如同一個交通警察站在來往的車輛流中
決定放行那一個方向的車輛向那一個方向流動一樣
而本節要討論的工廠方法模式是簡單工廠模式的進一步抽象化和推廣
它比簡單工廠模式聰明的地方在於
它不再作為一個具體的交通警察的面貌出現
而是以交通警察局的面貌出現
它把具體的車輛交通交給下面去管理
換言之
工廠方法模式裡不再只由一個工廠類決定那一個產品類應當被實例化
這個決定被交給子類去作
處於工廠方法模式的中心位置上的類甚至都不去接觸那一個產品類應當被實例化這種細節
這種進一步抽象化的結果
是這種新的模式可以用來處理更加復雜的情形
為什麼需要工廠方法模式
現在
讓我們繼續考察我們的小花果園
在<簡單工廠模式>一節裡
我們在後花園裡引進了水果類植物
構造了簡單工廠模式來處理
使用一個FruitGardener類來負責創立水果類的實例
見下圖
圖
簡單工廠模式
FruitGardener掌握所有水果類的生殺大權
在這一節裡
我們准備再次引進蔬菜類植物
比如
西紅柿 (Tomato)
土豆 (Potato)
西芥蘭花 (Broccoli)
蔬菜與花和水果當然有共同點
可又有不同之處
蔬菜需要噴灑(dust)殺蟲劑(pesticide)除蟲
不同的蔬菜需要噴灑不同的殺蟲劑
等等
怎麼辦呢?
那麼
再借用一下簡單工廠模式不就行了? 再設計一個專管蔬菜類植物的工廠類
比如
圖
簡單工廠模式
VeggieGardener掌握所有蔬菜類的生殺大權
這樣做一個明顯的不足點就是不夠一般化和抽象化
在FruitGardener和VeggieGardener類之間明顯存在很多共同點
這些共同點應當抽出來一般化和框架化
這樣一來
如果後花園的主人決定再在園子裡引進些樹木類植物時
我們有框架化的處理方法
本節所要引入的工廠方法模式就符合這樣的要求
簡單工廠模式的回顧
有必要首先回顧一下簡單工廠模式的定義
以便於比較
圖
簡單工廠模式的類圖定義
從上圖可以看出
簡單工廠模式涉及到以下的角色
工廠類 (Creator)
擔任這個角色的是工廠方法模式的核心
是與應用程序緊密相關的
直接在應用程序調用下
創立產品實例的那個類
工廠類只有一個
而且是實的
見下面的位圖
產品 (Product)
擔任這個角色的類是工廠方法模式所創立的對象的父類
或它們共同擁有的接口
實產品 (Concrete Product)
擔任這個角色的類是工廠方法模式所創立的任何對象所屬的類
實產品類可以是分布在一維數軸上的分立點
中的任何一個
見下面的位圖
工廠方法模式的定義
我們給出工廠方法模式的類圖定義如下
圖
工廠方法模式的類圖定義
從上圖可以看出
工廠方法模式涉及到以下的角色
抽象工廠接口(Creator)
擔任這個角色的是工廠方法模式的核心
它是與應用程序無關的
任何在模式中創立對象的工廠類必須實現這個接口
實工廠類 (Conrete Creator)
擔任這個角色的是與應用程序緊密相關的
直接在應用程序調用下
創立產品實例的那樣一些類
實工廠類可以是分布在一維數軸上的分立點
中的任何一個
見下面的位圖
產品 (Product)
擔任這個角色的類是工廠方法模式所創立的對象的父類
或它們共同擁有的接口
實產品 (Concrete Product)
擔任這個角色的類是工廠方法模式所創立的任何對象所屬的類
實產品類可以是分布在二維平面上的分立點 (
)
(
)
(
)
中的任何一個
見下面的位圖
由實工廠
(橫數軸上第一點)創立的對象來自實產品類(
)
(
)
(
)
由實工廠
(橫數軸上第二點)創立的對象來自實產品類(
)
(
)
(
)
依此類推
工廠方法模式和簡單工廠模式在定義上的不同是很明顯的
工廠方法模式的核心是一個抽象工廠類
而不像簡單工廠模式
把核心放在一個實類上
工廠方法模式可以允許很多實的工廠類從抽象工廠類繼承下來
從而可以在實際上成為多個簡單工廠模式的綜合
從而推廣了簡單工廠模式
反過來講
簡單工廠模式是由工廠方法模式退化而來
設想如果我們非常確定一個系統只需要一個實的工廠類
那麼就不妨把抽象工廠類合並到實的工廠類中去
而這樣一來
我們就退化到簡單工廠模式了
與簡單工廠模式中的情形一樣的是
ConcreteCreator 的factory() 方法返還的數據類型是一個接口 PlantIF
而不是哪一個具體的產品類
這種設計使得工廠類創立哪一個產品類的實例細節完全封裝在工廠類內部
工廠方法模式又叫多形性工廠模式
顯然是因為實工廠類都有共同的接口
或者都有共同的抽象父類
工廠方法模式在小花果園系統中的實現
好了
現在讓我們回到小花果園的系統裡
看一看怎樣發揮工廠方法模式的威力
解決需要接連不斷向小花果園引進不同類別的植物所帶來的問題
首先
我們需要一個抽象工廠類
比如叫做 Gardener
作為兩個實工廠類 FruitGardener 及 VeggieGardener 的父類
Gardener 的 factory() 方法可以是抽象的
留給子類去實現
也可以是實的
在父類實現一部分功能
再在子類實現剩余的功能
我們選擇將 factory() 做成抽象的
主要是因為我們的系統是一個示范系統
內容十分簡單
沒有要在父類實現的任何功能
圖
工廠方法模式在小花果園系統中的實現
抽象工廠類 Gardener 是工廠方法模式的核心
但是它並不掌握水果類或蔬菜類的生殺大權
相反地
這項權力被交給子類
即 VeggieGardener 及 FruitGardener
package com
javapatterns
factorymethod;
abstract public class Gardener
{
public abstract PlantIF factory(String which) throws BadFruitException;
}
代碼清單
父類 Gardener
package com
javapatterns
factorymethod;
public class VeggieGardener extends Gardener
{
public PlantIF factory(String which) throws BadPlantException
{
if (which
equalsIgnoreCase(
tomato
))
{
return new Tomato();
}
else if (which
equalsIgnoreCase(
potato
))
{
return new Potato();
}
else if (which
equalsIgnoreCase(
broccoli
))
{
return new Broccoli();
}
else
{
throw new BadPlantException(
Bad veggie request
);
}
}
}
代碼清單
子類 VeggieGardener
package com
javapatterns
factorymethod;
public class FruitGardener extends Gardener
{
public PlantIF factory(String which)
{
if (which
equalsIgnoreCase(
apple
))
{
return new Apple();
}
else if (which
equalsIgnoreCase(
strawberry
))
{
return new Strawberry();
}
else if (which
equalsIgnoreCase(
grape
))
{
return new Grape();
}
else
{
throw new BadPlantException(
Bad fruit request
);
}
}
}
代碼清單
子類 FruitGardener
package com
javapatterns
factorymethod;
public class Broccoli implements VeggieIF
PlantIF
{
public void grow()
{
log(
Broccoli is growing
);
}
public void harvest()
{
log(
Broccoli has been harvested
);
}
public void plant()
{
log(
Broccoli has been planted
);
}
private static void log(String msg)
{
System
out
println(msg);
}
public void pesticideDust(){ }
}
代碼清單
蔬菜類 Broccoli
其它的蔬菜類與 Broccoli 相似
因此不再贅述
package com
javapatterns
factorymethod;
public class Apple implements FruitIF
PlantIF
{
public void grow()
{
log(
Apple is growing
);
}
public void harvest()
{
log(
Apple has been harvested
);
}
public void plant()
{
log(
Apple has been planted
);
}
From:http://tw.wingwit.com/Article/program/Java/gj/201311/27652.html