來源:北大青鳥總部 2023年02月16日 14:40
在程序猿世界里,能夠?qū)懗鰞?yōu)雅、可擴(kuò)展、低耦合、甚至像詩一樣的代碼,是每個(gè)程序猿畢生的追求~
秉承這個(gè)人生的終極理想,猿小二入職一家新公司,開始慢慢熟悉公司的代碼,越來越覺得不對(duì)勁,這家公司的代碼寫的可真爛,各種耦合牽一發(fā)動(dòng)全身,完全不是面試時(shí)老板說的公司的代碼都像詩一樣優(yōu)雅,猿小二感覺自己上當(dāng)了!
沒辦法,猿小二只能硬著頭皮繼續(xù)了,不過猿小二轉(zhuǎn)念一想,代碼這么多問題,不就是給我表現(xiàn)的機(jī)會(huì)嗎?猿小二心中竊喜,思考著如何用設(shè)計(jì)模式來重構(gòu)現(xiàn)在的代碼,增加程序間的可擴(kuò)展性并降低程序間的耦合度,猿小二想到最近正在研究的工廠模式,于是猿小二開始了他的改造之旅......
經(jīng)過了一段時(shí)間的努力,猿小二終于完成了一部分代碼的改造;正當(dāng)他在對(duì)自己的成就自信滿滿的時(shí)候,一些同事突然過來說改造之后的代碼雖然感覺很優(yōu)雅(不明覺厲),但是他們卻看不懂,猿小二說,我來給大家講一下我的改造之旅吧,其實(shí)也不是那么順利的,于是猿小二又開始了他的分享之旅~~~
最開始的時(shí)候,猿小二對(duì)一些代碼的改造使用了簡(jiǎn)單工廠模式,簡(jiǎn)單工廠就是有一個(gè)工廠類,根據(jù)傳入的參數(shù)不同創(chuàng)建不同的對(duì)象實(shí)例;比如說,有個(gè)生產(chǎn)汽車的工廠(CarFactory),可以生產(chǎn)各種不同品牌的汽車(AudiCar、BWMCar、AMGCar)
定義一個(gè)汽車的接口
/** * 汽車接口 */ public interface Car { // 汽車會(huì)跑 public void run(); } |
定義各種品牌的汽車類,實(shí)現(xiàn)汽車接口
/** * 奧迪汽車類 */ public class AudiCar implements Car { public void run() { System.out.println("奧迪汽車..."); } } |
/** * 寶馬汽車類 */ public class BWMCar implements Car { public void run() { System.out.println("寶馬汽車..."); } } |
對(duì)于這些不同品牌的汽車我們就可以提供一個(gè)工廠類,來根據(jù)不同的品牌參數(shù)去生產(chǎn)不同的汽車
/** * 汽車工廠 */public class CarFactory { // 生產(chǎn)不同品牌的汽車 public Car produce(String bank) { if ("AudiCar".equals(bank)) { return new AudiCar(); } else if ("BWMCar".equals(bank)) { return new BWMCar(); } return null; } } |
有了工廠對(duì)象了,接下來就可以生產(chǎn)汽車了
/** * 測(cè)試生產(chǎn)汽車 */ public class CarTest { public static void main(String[] args) { // 創(chuàng)建汽車工廠 CarFactory carFactory = new CarFactory(); // 生產(chǎn)奧迪汽車 Car audi = carFactory.produce("Audi"); audi.run(); // 生產(chǎn)寶馬汽車 Car bwm = carFactory.produce("BWM"); bwm.run(); } } |
這樣以來的話,我們就可以不用關(guān)心具體汽車對(duì)象的生產(chǎn)過程,只需要根據(jù)傳遞的參數(shù)(汽車品牌)就可以創(chuàng)建需要的汽車品牌了。
不過還有一個(gè)問題,就是如果我們要生產(chǎn)其他品牌的汽車,比如:豐田汽車,就的去改工廠類CarFactory里代碼,如果是汽車品牌多了話,豈不是要經(jīng)常修改,這種頻繁修改的代碼的行為,這顯然不符合開放-封閉原則,對(duì)于追求極致的猿小二來說,顯然是接受不了的,于是他有開始新一輪的改造。
這個(gè)時(shí)候,猿小二想到了工廠方法模式,不同于簡(jiǎn)單工廠模式的是,工廠方法模式?jīng)]有使用統(tǒng)一的工廠去生產(chǎn)不同的汽車品牌,而是分別給不同的汽車品牌建設(shè)不同工廠,比如:要生產(chǎn)Audi汽車,就創(chuàng)建Audi的汽車工廠;這樣每一個(gè)汽車品牌都有自己獨(dú)立的汽車生產(chǎn)工廠。
首先,先抽取一個(gè)最頂層的汽車工廠接口
/** * 汽車工廠 */ public interface CarFactory { // 生產(chǎn)汽車 public Car produce(); } |
然后,讓不同的汽車品牌工廠都實(shí)現(xiàn)這個(gè)接口,比如:奧迪汽車工廠、寶馬汽車工廠、豐田汽車工廠。
/** * 奧迪汽車工廠 */ public class AudiCarFactory implements CarFactory { // 負(fù)責(zé)生產(chǎn)奧迪汽車 public Car produce() { return new AudiCar(); } } |
豐田汽車工廠
/** * 豐田汽車廠 */ public class TOYOTACarFactory implements CarFactory { // 負(fù)責(zé)生產(chǎn)豐田汽車 public Car produce() { return new TOYOTACar(); } } |
測(cè)試生產(chǎn)汽車
/** * 汽車工廠方法測(cè)試 */ public class CarFactoryMethodTest { public static void main(String[] args) { // 奧迪汽車廠生產(chǎn)奧迪汽車 CarFactory audiCarFactory = new AudiCarFactory(); Car audi = audiCarFactory.produce(); audi.run(); // 寶馬汽車廠生產(chǎn)寶馬汽車 CarFactory toyotaCarFactory = new TOYOTACarFactory(); Car toyota = toyotaCarFactory.produce(); toyota.run(); } } |
通過這種工廠方法模式,我們?cè)僖膊挥脫?dān)心增加汽車品牌而去修改汽車工廠的代碼了,只需要?jiǎng)?chuàng)建相應(yīng)品牌的汽車工廠類就可以了,而且這種方式還符合了設(shè)計(jì)模式的開放-封閉原則,簡(jiǎn)直是完美;雖然有可能隨著汽車品牌的增加,工廠類也不斷增加,一定程度上會(huì)增加系統(tǒng)的復(fù)雜度,但是相對(duì)于它帶來的好處還是可以接受的。
本來事情已經(jīng)告一段落,猿小二可以稍微輕松下了,沒想到老板說又有新的需求了,這些汽車廠要涉足汽車發(fā)動(dòng)機(jī)領(lǐng)域,想要自己生產(chǎn)汽車發(fā)動(dòng)機(jī),這可難壞了猿小二,本來按照原來的思路,可以在創(chuàng)建發(fā)動(dòng)機(jī)的工廠類,但是考慮到制造成本(發(fā)動(dòng)機(jī)和組裝在同一個(gè)工廠生產(chǎn)),準(zhǔn)備對(duì)原來的汽車工廠進(jìn)行改造。
為了滿足新的需求,需要在對(duì)原來的工廠進(jìn)行改造,增加生產(chǎn)發(fā)動(dòng)機(jī)的方法,這種方式就涉及到另外一種抽象工廠模式,在抽象工廠模式中,每一個(gè)具體工廠都提供了多個(gè)工廠方法用于產(chǎn)生多種不同類型的對(duì)象,比如,汽車工廠既生產(chǎn)汽車,也生產(chǎn)汽車發(fā)動(dòng)機(jī),于是猿小二開始新一輪的改造。
首先,我們先定義抽象工廠類,它既可以生產(chǎn)汽車,也可以生產(chǎn)汽車發(fā)動(dòng)機(jī)
/** * 抽象工廠 */ public interface CarAbstractFactory { // 生產(chǎn)汽車 public Car produce(); // 生產(chǎn)發(fā)動(dòng)機(jī) public Engine createEngine(); } |
奧迪汽車工廠類實(shí)現(xiàn)這個(gè)抽象接口,生產(chǎn)奧迪汽車和奧迪的發(fā)動(dòng)機(jī)
/** * 奧迪汽車工廠 */ public class AudiCarFactory implements CarAbstractFactory { // 負(fù)責(zé)生產(chǎn)奧迪汽車 public Car produce() { return new AudiCar(); } // 生產(chǎn)奧迪發(fā)動(dòng)機(jī) public Engine create() { return new AudiEngie(); } } |
這樣我們就可以看到奧迪汽車廠就可以生產(chǎn)自己品牌的汽車和發(fā)動(dòng)機(jī),其他品牌也可以生產(chǎn)各自的汽車和發(fā)動(dòng)機(jī)
/** * 抽象工廠測(cè)試 */ public class AbstractFactoryTest { public static void main(String[] args) { // 奧迪汽車廠 CarAbstractFactory audiCarFactory = new AudiCarFactory(); // 生產(chǎn)奧迪汽車 Car produce = audiCarFactory.produce(); produce.run(); // 生產(chǎn)奧迪汽車發(fā)動(dòng)機(jī) Engine audiengine = audiCarFactory.createEngine(); audiengine.createEngine(); } } |
從這里我們可以看出其實(shí)抽象工廠模式是一個(gè)工廠可以生產(chǎn)多個(gè)產(chǎn)品類,也就是一系列相互關(guān)聯(lián)的產(chǎn)品,比如:汽車和發(fā)動(dòng)機(jī)。
其實(shí),無論是簡(jiǎn)單工廠模式,工廠方法模式,還是抽象工廠模式,他們都屬于工廠模式,雖然在形式有些區(qū)別,但是最終目的都是為了解耦。在使用時(shí),我們不必去在意這個(gè)模式到底工廠方法模式還是抽象工廠模式,因?yàn)橥ǔG闆r下是結(jié)合使用;經(jīng)常你會(huì)發(fā)現(xiàn),明明使用的工廠方法模式,當(dāng)新需求來臨,稍加修改,加入了一個(gè)新方法后,由于類中的產(chǎn)品構(gòu)成了不同等級(jí)結(jié)構(gòu)中的產(chǎn)品族,它就變成抽象工廠模式了;而對(duì)于抽象工廠模式,當(dāng)減少一個(gè)方法使的提供的產(chǎn)品不再構(gòu)成產(chǎn)品族之后,它就演變成了工廠方法模式;所以,在使用工廠模式時(shí),只需要關(guān)心是不是達(dá)到我們的業(yè)務(wù)需求,并且最大限度降低系統(tǒng)間的耦合度。