package com
javapatterns
factorymethod;
public class BadPlantException extends Exception
{
public BadPlantException(String msg)
{
super(msg);
}
}
代碼清單
例外類 BadPlantException
工廠方法模式應該在什麼情況下使用
既然工廠方法模式與簡單工廠模式的區別很是微妙
那麼應該在什麼情況下使用工廠方法模式
又應該在什麼情況下使用簡單工廠模式呢?
一般來說
如果你的系統不能事先確定那一個產品類在哪一個時刻被實例化
從而需要將實例化的細節局域化
並封裝起來以分割實例化及使用實例的責任時
你就需要考慮使用某一種形式的工廠模式
在我們的小花果園系統裡
我們必須假設水果的種類隨時都有可能變化
我們必須能夠在引入新的水果品種時
能夠很少改動程序
就可以適應變化以後的情況
因此
我們顯然需要某一種形式的工廠模式
如果在發現系統只用一個產品類等級(hierarchy)就可以描述所有已有的產品類
以及可預見的未來可能引進的產品類時
簡單工廠模式是很好的解決方案
因為一個單一產品類等級只需要一個單一的實的工廠類
然而
當發現系統只用一個產品類等級不足以描述所有的產品類
包括以後可能要添加的新的產品類時
就應當考慮采用工廠方法模式
由於工廠方法模式可以容許多個實的工廠類
以每一個工廠類負責每一個產品類等級
因此這種模式可以容納所有的產品等級
在我們的小花果園系統裡
不只有水果種類的植物
而且有蔬菜種類的植物
換言之
存在不止一個產品類等級
而且產品類等級的數目也隨時都有可能變化
因此
簡單工廠模式不能滿足需要
為解決向題
我們顯然需要工廠方法模式
關於模式的實現
在實現工廠方法模式時
有下面一些值得討論的地方
第一丶在圖四的類圖定義中
可以對抽象工廠(Creator) 做一些變通
變通的種類有
抽象工廠(Creator) 不是接口而是抽象類
一般而言
抽象類不提供一個缺省的工廠方法
這樣可以有效地解決怎樣實例化事先不能預知的類的問題
抽象工廠(Creator) 本身是一個實類
並提供一個缺省的工廠方法
這樣當最初的設計者所預見的實例化不能滿足需要時
後來的設計人員就可以用實工廠類的factory() 方法來置換(Override))父類中factory()方法
第二丶在經典的工廠方法模式中
factory()方法是沒有參量的
在本文舉例時加入了參量
這實際上也是一種變通
第三丶在給相關的類和方法取名字時
應當注意讓別人一看即知你是在使用工廠模式
COM技術架構中的工廠方法模式
在微軟(Microsoft)所提倡的COM(Component Object Model)技術架構中
工廠方法模式起著關鍵的作用
在COM架框裡
Creator接口的角色是由一個叫作IClassFactory的COM接口來擔任的
而實類ConcreteCreator的角色是由實現IClassFactory接口的類CFactory(見下圖)來擔任的
一般而言
對象的創立可能要求分配系統資源
要求在不同的對象之間進行協調等等
因為IClassFactory的引進
所有這些在對象的創立過程中出現的細節問題
都可以封裝在一個實現IClassFactory接口的實的工廠類裡面
這樣一來
一個COM架構的支持系統只需要創立這個工廠類CFactory的實例就可以了
圖
微軟(Microsoft)的COM(Component Object Model)技術架構是怎樣工作的
在上面的序列活動(Sequence Activity)圖中
用戶端調用COM的庫函數CoCreateInstance
CoCreateInstance在COM架框中以CoGetClassObject實現
CoCreateInstance會在視窗系統的Registry裡搜尋所要的部件(在我們的例子中即CEmployee)
如果找到了這個部件
就會加載支持此部件的DLL
當此DLL加載成功後
CoGetClassObject就會調用DllGetClassObject
後者使用new操作符將工廠類CFactory實例化
下面
DllGetClassObject會向工廠類CFactory搜詢IClassFactory接口
返還給CoCreateInstance
CoCreateInstance接下來利用IClassFactory接口調用CreateInstance函數
此時
IClassFactory::CreateInstance調用new操作符來創立所要的部件(CEmployee)
此外
它搜詢IEmployee接口
在拿到接口的指針後
CoCreateInstance釋放掉工廠類並把接口的指針返還給客戶端
客戶端現在就可以利用這個接口調用此部件中的方法了
EJB技術架構中的工廠方法模式
升陽(Sun Microsystem)倡導的EJB(Enterprise Java Beans)技術架構是一套為爪哇語言設計的
用來開發企業規模應用程序的組件模型
我們來舉例看一看EJB架構是怎樣利用工廠方法模式的
請考察下面的序列活動圖
圖
在升陽所提倡的EJB技術架構中
工廠方法模式也起著關鍵的作用
在上面的圖中
用戶端創立一個新的 Context 對象
以便利用 JNDI 伺服器尋找 EJBObject
在得到這個 Context 對象後
就可以使用 JNDI 名
比如
Employee
來拿到 EJB 類 Employee 的 Home 接口
使用 Employee 的 Home 接口
客戶端可以創立 EJB 對象
比如 EJB 類 Employee 的實例 emp
然後調用 Employee 的各個方法
// 取到 JNDI naming context
Context ctx = new InitialContext ();
// 利用ctx 索取 EJB Home 接口
EmployeeHome home = (EmployeeHome)ctx
lookup(
Employee
);
// 利用Home 接口創立一個 Session Bean 對象
// 這裡使用的是標准的工廠方法模式
Employee emp = home
create (
John
Smith
);
// 調用方法
emp
setTel (
);
代碼清單
EJB架構中
Home接口提供工廠方法以便用戶端可以動態地創立EJB類Employee的實例
JMS技術架構中的工廠方法模式
JMS定義了一套標准的API
讓爪哇語言程序能通過支持JMS標准的MOM(Message Oriented Middleware 面向消息的中間伺服器)來創立和交換消息(message)
我們來舉例看一看JMS(Java Messaging Service)技術架構是怎樣使用工廠方法模式的
圖
在JMS技術架構中
工廠方法模式無處不在
在上面的序列圖中
用戶端創立一個新的 Context 對象
以便利用 JNDI 伺服器尋找 Topic 和 ConnectionFactory 對象
在得到這個 ConnectionFactory 對象後
就可以利用 Connection 創立 Session 的實例
有了 Session 的實例後
就可以利用 Session 創立 TopicPublisher的實例
並利用Session創立消息實例
Properties prop = new Properties();
prop
put(Context
INITIAL_CONTEXT_FACTORY
com
sun
jndi
fscontext
RefFSContextFactory
);
prop
put(Context
PROVIDER_URL
file:C:\temp
);
// 取到 JNDI context
Context ctx = new InitialContext(prop);
// 利用ctx 索取工廠類的實例
Topic topic = (Topic) ctx
lookup(
myTopic
);
TopicConnectionFactory tcf = (TopicConnectionFactory) ctx
lookup(
myTCF
);
// 利用工廠類創立Connection
這是典型的工廠模式
TopicConnection tCon = tcf
createTopicConnectoin();
// 利用Connection創立Session的實例
又是工廠模式
TopicSession tSess = tCon
createTopicSession(false
Session
AUTO_ACKNOWLEDGE);
// 利用Session創立Producer的實例
又是工廠模式
TopicPublisher publisher = tSess
createPublisher(topic);
// 利用Session創立消息實例
又是工廠模式
TextMesage msg = tSess
createTextMessage(
Hello from Jeff
);
//發送消息
publisher
publish(msg);
代碼清單
JMS架構中
工廠模式被用於創立 Connection
Session
Producer 的實例
問答題
第
題
在這一節和上一節的類圖中
我注意到Apple類的類圖與Strawberry類的類圖有一點點不同
在Apple類的類圖左上角有一個夾子樣的標識
請問這個標識代表什麼意思
第
題
在這一節的類圖
中
我注意到 ConcreteProduct 類只出現一次
但實現 Product 接口的類實際上可以有很多
這是否可以用在聯接 Product 和 ConcreteProduct 之間的線旁注上
表示呢? 記得我在UML圖中曾見過這種記號
第
題
請問在本節的小花果園系統的源代碼清單
裡
Broccoli 類實現兩個接口
VeggieIF 和 PlantIF
只有 PlantIF 才與工廠模式有關
為什麼不把 VeggieIF 接口合並到 PlantIF 接口中去?
第
題
請問在工廠方法模式中
產品(Product) 何時應是抽象類
何時應是接口?
第
題
請問在工廠方法 (factory())中
為什麼要使用 if 語句作過程性判斷來決定創立哪一個產品類
而不使用多形性原則 (Polymorphsm) 來創立產品類?
問答題答案
第
題
Apple類有性質(property)
而Strawberry類沒有性質
一個類的成員變量叫做屬性(attribute)
性質與屬性的區別在於性質是帶著一套取值丶賦值方法的屬性
一個類有了屬性
其類圖左上角就會有一只夾子
有些人認為
一個爪哇類有了屬性才能被稱做爪哇豆(Java Bean)
這只夾子就表示這個類是一只豆
一個企業爪哇豆
或 EJB (Enterprise JavaBean) 的類圖左上角也會有一只夾子
夾子上面有一個E字以示與普通的爪哇豆的不同(請見下圖)
第
題
不能
在圖
中聯接 Product 和 ConcreteProduct 之間的線有兩條
一條表示兩者之間的推廣關系 (即有向上箭頭的)
另一條表示兩者之間
From:http://tw.wingwit.com/Article/program/Java/gj/201311/27447.html