設計模式——工廠方法模式

精選推薦:設計模式——簡單工廠設計模式——觀察者模式設計模式——裝飾者模式
所有的工廠模式都用來封裝對象的創(chuàng)建。工廠方法模式通過讓子類決定該創(chuàng)建的對象是什么,來達到將對象創(chuàng)建的過程封裝的目的。
設計原則
依賴倒置原則
要依賴抽象,不要依賴具體類
定義
工廠方法模式定義了一個創(chuàng)建對象的接口,但由子類決定要實例化的類是哪一個。工廠方法讓類把實例化推遲到子類。
如同定義中所說的,工廠方法讓子類決定要實例化的類是哪一個。所謂的“決定”,并不是指模式允許子類本身在運行時做決定,而是指在編寫創(chuàng)建者類時,不需要知道實際創(chuàng)建的產(chǎn)品是哪一個。選擇了使用哪個子類,自然就決定了實際創(chuàng)建的產(chǎn)品是什么。
類圖

代碼實現(xiàn)
我們還是以上面咖啡店為例。
一個大的咖啡店不可能只有一個,而是遍布在全國各地,上海、北京、深圳……都會有分店。而且如果經(jīng)營的好,分店還會增加。
那么,每個地區(qū)的分店雖然都是售賣咖啡,但是為了滿足各地區(qū)客戶的需求偏好,也會根據(jù)當?shù)靥厣行┰S的不同。比如上海人喜歡吃甜的,那么上海分店可能生產(chǎn)出來的同樣的咖啡味道為偏甜,北京人口味偏咸和鮮,講究濃,那么同樣的咖啡口味就會更濃,深圳屬于南方,口味清淡,那可能就會是原味咖啡居多,不放牛奶也不放糖,濃淡適中……
對于咖啡廳,從制作好咖啡到送到客戶手中還需要一系列步驟,比如打包……,而這個打包的過程程序就與咖啡的類別沒有太大關系。
下面我們用代碼來實現(xiàn):
package?com.study.design.Factory.factorymethod;
/**
?*?被生產(chǎn)對象的抽象父類
?*/
public?abstract?class?Coffe?{
????protected?String?coffeName;
????public?String?getCoffeName()?{
????????return?coffeName;
????}
}
package?com.study.design.Factory.factorymethod;
public?class?SHLatteCoffe?extends?Coffe{
????public?SHLatteCoffe(){
????????coffeName?=?"shanghai?latte";
????};
}
package?com.study.design.Factory.factorymethod;
public?class?SHMochaCoffe?extends?Coffe{
????public?SHMochaCoffe(){
????????coffeName?=?"shanghai?mocha";
????}
}
package?com.study.design.Factory.factorymethod;
public?class?BJLatteCoffe?extends?Coffe{
????public?BJLatteCoffe(){
????????coffeName?=?"beijing?latte";
????}
}
package?com.study.design.Factory.factorymethod;
public?class?BJMochaCoffe?extends?Coffe{
????public?BJMochaCoffe(){
????????coffeName?=?"beijing?mocha";
????}
}
package?com.study.design.Factory.factorymethod;
public?class?SZLatteCoffe?extends?Coffe{
????public?SZLatteCoffe(){
????????coffeName?=?"shenzhen?latte";
????}
}
package?com.study.design.Factory.factorymethod;
public?class?SZMochaCoffe?extends?Coffe{
????public?SZMochaCoffe(){
????????coffeName?=?"shenzhen?mocha";
????}
}?
package?com.study.design.Factory.factorymethod;
/**
?*?咖啡店,現(xiàn)在它是個抽象類
?*?完成生產(chǎn)咖啡的所有工序,但是生產(chǎn)咖啡的具體口味由子類決定
?*/
public?abstract?class?CoffeStores?{
????/**
?????*?生產(chǎn)咖啡的工廠方法
?????*?@param?type
?????*?@return
?????*/
????public?Coffe?productCoffe(int?type){
????????Coffe?coffe?=?makeCoffe(type);
????????box();
????????return?coffe;
????}
????/**
?????*?打包
?????*/
????private?void?box(){
????????System.out.println("packed……");
????}
????/**
?????*?工廠方法
?????*?生產(chǎn)咖啡的動作交由子類實現(xiàn)
?????*?@param?type
?????*?@return
?????*/
????protected?abstract?Coffe?makeCoffe(int?type);
}
package?com.study.design.Factory.factorymethod;
/**
?*?工廠類
?*?上海咖啡店
?*/
public?class?SHCoffeStores?extends?BJCoffeStores?{
????@Override
????protected?Coffe?makeCoffe(int?type)?{
????????if?(1?==?type){
????????????return?new?SHMochaCoffe();
????????}else{
????????????return?new?SHLatteCoffe();
????????}
????}
}
package?com.study.design.Factory.factorymethod;
public?class?BJCoffeStores?extends?CoffeStores{
????@Override
????protected?Coffe?makeCoffe(int?type)?{
????????if?(1?==?type){
????????????return?new?BJMochaCoffe();
????????}else?{
????????????return?new?BJLatteCoffe();
????????}
????}
}
package?com.study.design.Factory.factorymethod;
public?class?SZCoffeStores?extends?CoffeStores{
????@Override
????protected?Coffe?makeCoffe(int?type)?{
????????if?(1?==?type){
????????????return?new?SZMochaCoffe();
????????}else{
????????????return?new?SZLatteCoffe();
????????}
????}
}
package?com.study.design.Factory.factorymethod;
public?class?SHConsumer?{
????private?CoffeStores?coffeStores;
????public?SHConsumer(CoffeStores?coffeStores){
????????this.coffeStores?=?coffeStores;
????}
????public?void?drink(int?type){
????????Coffe?coffe?=?coffeStores.productCoffe(type);
????????System.out.println("I?got?a?cup?of?"?+?coffe.getCoffeName());
????}
}
package?com.study.design.Factory.factorymethod;
public?class?BJConsumer?{
????private?CoffeStores?coffeStores;
????public?BJConsumer(CoffeStores?coffeStores){
????????this.coffeStores?=?coffeStores;
????}
????public?void?drink(int?type){
????????Coffe?coffe?=?coffeStores.productCoffe(type);
????????System.out.println("I?got?a?cup?of?"?+?coffe.getCoffeName());
????}
}
package?com.study.design.Factory.factorymethod;
public?class?SZConsumer?{
????private?CoffeStores?coffeStores;
????public?SZConsumer(CoffeStores?coffeStores){
????????this.coffeStores?=?coffeStores;
????}
????public?void?drink(int?type){
????????Coffe?coffe?=?coffeStores.productCoffe(type);
????????System.out.println("I?got?a?cup?of?"?+?coffe.getCoffeName());
????}
}
package?com.study.design.Factory.factorymethod;
public?class?FactoryMethodTest?{
????public?static?void?main(String[]?args)?{
????????//?創(chuàng)建三個地區(qū)的咖啡廳實例
????????SHCoffeStores?shCoffeStores?=?new?SHCoffeStores();
????????BJCoffeStores?bjCoffeStores?=?new?BJCoffeStores();
????????SZCoffeStores?szCoffeStores?=?new?SZCoffeStores();
????????//?創(chuàng)建三個地區(qū)的消費者
????????SHConsumer?shConsumer?=?new?SHConsumer(shCoffeStores);
????????BJConsumer?bjConsumer?=?new?BJConsumer(bjCoffeStores);
????????SZConsumer?szConsumer?=?new?SZConsumer(szCoffeStores);
????????//?消費者消費各自地區(qū)的咖啡
????????shConsumer.drink(1);
????????bjConsumer.drink(2);
????????szConsumer.drink(1);
????}
}
要點
- 所謂工廠方法,就是有一個方法起到工廠創(chuàng)建對象的作用。這個方法定義為抽象的,依賴子類處理對象的創(chuàng)建。而在父類中又可以定義一些所有對象通用的行為,比如打包……。
- 每個抽象方法的具體實現(xiàn)子類,又可以看做是一個簡單工廠。一般只負責創(chuàng)建實例對象。
- 使用者通過選擇不同的子類來獲取不同的對象
簡單工廠與工廠方法模式的區(qū)別:
簡單工廠把全部的事情,在一個地方都處理完了,而工廠方法卻是創(chuàng)建一個框架,讓子類決定如何實現(xiàn)具體對象的創(chuàng)建。簡單工廠可以將對象創(chuàng)建出來,但是簡單工廠不具備工廠方法的彈性,因為簡單工廠不能變更正在創(chuàng)建的產(chǎn)品。
當只有一個 SHCoffeStores 的時候,工廠方法模式有什么優(yōu)點?
盡管只有一個具體創(chuàng)建者,工廠方法模式依然很有用,它幫助我們將產(chǎn)品的“實現(xiàn)”從“使用”中解耦。如果增加新的咖啡品種,CoffeStores 不會受到影響,因為 CoffeStores 與任何 SHCoffeStores 之間都不是緊耦合的。
