小A:“什麼是簡單工廠模式?”
大B:“簡單工廠模式又叫靜態(tài)工廠模式,顧名思義,它是用來實例化目標類的靜態(tài)類。”
小A:“簡單工廠模式有什麼優(yōu)點?”
大B:“現(xiàn)在我就主要通過一個簡單的實例說明簡單工廠及其優(yōu)點。”
小A:“嗯。好。”
大B:“就如剛纔我講過的,有個國家的運動員協(xié)會。”
下面給出各個類的程序。
Code:[Copytoclipboard]
運動員.java
publicinterface運動員{
publicvoid跑();
publicvoid跳();
}
足球運動員.java
publicclass足球運動員implements運動員{
publicvoid跑(){
//跑啊跑
}
publicvoid跳(){
//跳啊跳
}
}
籃球運動員.java
publicclass籃球運動員implements運動員{
publicvoid跑(){
//donothing
}
publicvoid跳(){
//donothing
}
}
體育協(xié)會.java
publicclass體育協(xié)會{
publicstatic運動員註冊足球運動員(){
returnnew足球運動員();
}
publicstatic運動員註冊籃球運動員(){
returnnew籃球運動員();
}
}
俱樂部.java
publicclass俱樂部{
private運動員守門員;
private運動員後衛(wèi);
private運動員前鋒;
publicvoidtest(){
this前鋒=體育協(xié)會,註冊足球運動員();
this後衛(wèi)=體育協(xié)會,註冊足球運動員();
this守門員=體育協(xié)會,註冊足球運動員();
守門員,跑();
後衛(wèi),跳();
}
}
大B:“這就是簡單工廠模式的一個簡單實例,你應(yīng)該想象不用接口不用工廠而把具體類暴露給客戶端的那種混亂情形吧?就好像沒了體育總局,各個俱樂部在市場上自己胡亂的尋找仔細需要的運動員。簡單工廠就解決了這種混亂。我們用OCP看看簡單工廠,會發(fā)現(xiàn)如果要對系統(tǒng)進行擴展的話治需要增加實現(xiàn)產(chǎn)品接口的產(chǎn)品類(上例表現(xiàn)爲‘足球運動員’,‘籃球運動員’類,比如要增加個‘乒乓球運動員’類),而無需對原有的產(chǎn)品類進行修改。”
小A:“這咋一看好像滿足OCP。”
大B:“但是實際上還是需要修改代碼的——對,就是修改工廠類。上例中如果增加‘乒乓球運動員’產(chǎn)品類,就必須相應(yīng)的修改‘體育協(xié)會’工廠類,增加個‘註冊乒乓球運動員’方法。所以可以看出,簡單工廠模式是不滿足OCP的。”
小A:“那工廠方法模式哩?”
大B:“我們剛剛講了簡單工廠模式,下面繼續(xù)談?wù)劰S方法模式。剛纔點明瞭簡單工廠模式最大的缺點——不完全滿足OCP。爲了解決這一缺點,設(shè)計師們提出了工廠方法模式。工廠方法模式和簡單工廠模式最大的不同在於,簡單工廠模式只有一個(對於一個項目或者一個獨立模塊而言)工廠類,而工廠方法模式有一組實現(xiàn)了相同接口的工廠類。下面我們通過修改剛纔的實例來介紹工廠方法模式。我們在不改變產(chǎn)品類(‘足球運動員’類和‘籃球運動員’類)的情況下,修改下工廠類的結(jié)構(gòu)。”
相關(guān)代碼如下:
Code:[Copytoclipboard]
運動員.java
publicinterface運動員{
publicvoid跑();
publicvoid跳();
}
足球運動員.java
publicclass足球運動員implements運動員{
publicvoid跑(){
//跑啊跑
}
publicvoid跳(){
//跳啊跳
}
}
籃球運動員.java
publicclass籃球運動員implements運動員{
publicvoid跑(){
//donothing
}
publicvoid跳(){
//donothing
}
}
體育協(xié)會.java
publicinterface體育協(xié)會{
public運動員註冊();
}
足球協(xié)會.java
publicclass足球協(xié)會implements體育協(xié)會{
public運動員註冊(){
returnnew足球運動員();
}
}
籃球協(xié)會.java
publicclass籃球協(xié)會implements體育協(xié)會{
public運動員註冊(){
returnnew籃球運動員();
}
}
俱樂部.java
publicclass俱樂部{
private運動員守門員;
private運動員後衛(wèi);
private運動員前鋒;
publicvoidtest(){
體育協(xié)會中國足協(xié)=new足球協(xié)會();
this.前鋒=中國足協(xié),註冊();
this.後衛(wèi)=中國足協(xié),註冊();
守門員,跑();
後衛(wèi),跳();
}
}
大B:“很明顯可以看到,‘體育協(xié)會’工廠類變成了‘體育協(xié)會’接口,而實現(xiàn)此接口的分別是‘足球協(xié)會’‘籃球協(xié)會’等等具體的工廠類。”
小A:“這樣做有什麼好處呢?”
大B:“很明顯,這樣做就完全OCP了。如果需要再加入(或擴展)產(chǎn)品類(比如加多個‘乒乓球運動員’)的話就不再需要修改工廠類了,而只需相應(yīng)的再添加一個實現(xiàn)了工廠接口(‘體育協(xié)會’接口)的具體工廠類。”
小A:“工廠方法模式是爲了克服簡單工廠模式的缺點(主要是爲了滿足OCP)而設(shè)計出來的。但是,工廠方法模式就一定比簡單工廠模式好呢?”
大B:“不一定。1、結(jié)構(gòu)複雜度。從這個角度比較,顯然簡單工廠模式要佔優(yōu)。簡單工廠模式只需一個工廠類,而工廠方法模式的工廠類隨著產(chǎn)品類個數(shù)增加而增加,這無疑會使類的個數(shù)越來越多,從而增加了結(jié)構(gòu)的複雜程度。2、代碼複雜度。代碼複雜度和結(jié)構(gòu)複雜度是一對矛盾,既然簡單工廠模式在結(jié)構(gòu)方面相對簡潔,那麼它在代碼方面肯定是比工廠方法模式複雜的了。簡單工廠模式的工廠類隨著產(chǎn)品類的增加需要增加很多方法(或代碼),而工廠方法模式每個具體工廠類只完成單一任務(wù),代碼簡潔。3、客戶端編程難度。工廠方法模式雖然在工廠類結(jié)構(gòu)中引入了接口從而滿足了OCP,但是在客戶端編碼中需要對工廠類進行實例化。而簡單工廠模式的工廠類是個靜態(tài)類,在客戶端無需實例化,這無疑是個吸引人的優(yōu)點。4、管理上的難度。這是個關(guān)鍵的問題。我們先談擴展。衆(zhòng)所周知,工廠方法模式完全滿足OCP,即它有非常良好的擴展性。”
小A:“那是否就說明了簡單工廠模式就沒有擴展性呢?”
大B:“不是的。簡單工廠模式同樣具備良好的擴展性——擴展的時候僅需要修改少量的代碼(修改工廠類的代碼)就可以滿足擴展性的要求了。儘管這沒有完全滿足OCP,但不需要太拘泥於設(shè)計理論,要知道,sun提供的java官方工具包中也有好多沒有滿足OCP的例子啊(java.util.Calendar這個抽象類就不滿足OCP)。然後我們從維護性的角度分析下。假如某個具體產(chǎn)品類需要進行一定的修改,很可能需要修改對應(yīng)的工廠類。當同時需要修改多個產(chǎn)品類的時候,對工廠類的修改會變得相當麻煩(對號入座已經(jīng)是個問題了)。反而簡單工廠沒有這些麻煩,當多個產(chǎn)品類需要修改是,簡單工廠模式仍然僅僅需要修改唯一的工廠類。”