前言
在軟件設計過程中,我們總是需要創建很多對象,而且系統越龐大,創建的對象越復雜。而今天我們將討論的就是解決對象創建時的難題--工廠類模式。為了貼近工廠這個詞,我們采用工廠建造汽車這個例子來闡明工廠類模式的演變和什么場景下使用什么模式。
場景1、:一位顧客要開車從上海到蘇州,他需要一輛汽車,於是他自己組裝汽車,給車裝輪胎、導航儀、車燈等。
問題:1、顯然,顧客只是想擁有一輛汽車,他不想知道怎么去買汽車,更不想知道怎么組裝,然后還要給汽車上漆。
2、如果他想換個型號的汽車,他得重新來遍組裝汽車。
用代碼可以表示為:
首先我們需要一個汽車類
然后是客戶端參與制作汽車了
如果事實真的是這樣,估計顧客要吐血了,他只是想有輛車去蘇州,自己制作車太變態了,所以,他斷然不會這樣。如果他想要一輛其他型號的汽車,他需要改整個代碼。
這違反了設計模式的兩個原則:迪米特法則和開閉原則。客戶端只需要一輛車,秉承最小知道原則,顧客只需要得到一輛已經噴好漆、裝好空調的汽車。同時,對修改關閉也無法做到,如果顧客想換個型號的汽車,他需要修改大量的代碼。
這個場景現實肯定不會出現,現實是顧客會從一個工廠(公司)獲得一輛汽車。
場景2、上面那位顧客學聰明了,他從一個生產寶馬汽車的工廠購買了一輛汽車。
解決問題:屏蔽了汽車具體的建造細節,顧客再也不需要去學噴漆、裝發動機啦。
用代碼表示如下:
Car類還是不變,只是新增了個工廠類,把以前客戶端做的什么裝發動機的代碼讓工廠來完成。
客戶端代碼直接調用工廠類,獲得汽車,然后開始旅行就行了
由上面的代碼可以清晰的看到,客戶端對對象構建的具體細節,比如噴漆、安裝發動機都不知道,只是拿到了汽車,並可以駕駛她。這已經滿足了它的需求。而且如果想換一輛汽車,客戶端代碼不需要任何修改。
此場景中,運用到的設計模式是簡單工廠模式。
意圖:屏蔽客戶端對象實例化的具體細節;提供一個普通的創建對象的接口。
場景3、突然有一天,顧客賺了1個億,他告訴廠長他需要買很多汽車,可能是奔馳、或者是寶馬,也可能是法拉利。
面對問題:1、如何在保證原來生產線的正常運轉的前提下,生產奔馳和法拉利.
解決方法:1、廠長想,如果把3種汽車都放在一條生產線生產,那肯定不好,萬一新增的改動影響了以前的生產寶馬的生產線,就完蛋了(我們在寫代碼的時候,是不是經常簡單的修改原來的代碼,卻是冒着影響原來功能的風險呢?)。所以他新增了2個工廠,分別生產奔馳和法拉利。而且,如果以后需要生產新的車型,也直接新增一個工廠,只要遵守“抽象工廠”和顧客的約定即可,而不用擔心影響原來汽車的生產。
面對問題:2、現在有3個工廠,有3個廠長,如果顧客想買寶馬,就要找寶馬廠的廠長,買奔馳就要找奔馳廠的廠長。顧客肯定不願意,沒准一氣之下不買了。
解決方法:提供一個“抽象廠長”,他只和顧客協商,具體汽車的建造,由具體廠長去負責。
用代碼表示為:
定義了一個汽車的接口ICar,定義了汽車可以提供的服務,包括噴漆,裝空調,駕駛等。
上面的Car類稍微改動了下,就是實現了ICar接口。
客戶端代碼為:
然后再定義一個“抽象廠長”,負責和顧客約定購車協議。
再定義兩個工廠類具體生產奔馳和寶馬,他們遵循“抽象廠長”和顧客的約定,就是造車。
客戶端類如下:
現在可以看到,顧客代碼已經變得很簡潔了,而且工廠能快速新建各個工廠來生產汽車而不影響原來的汽車生產,這在快速變化的汽車行業中是很好的,而且提供給顧客的服務也越來越簡潔,這樣的企業,自然競爭力很強。
這里用到的設計模式為工廠方法模式:
意圖:定義一個用於創建對象的接口,讓子類決定實例化哪一個類,工廠方法使一個類的實例化延遲到其子類。
使用場景:1、當客戶程序不需要知道要使用對象的創建過程。
2、當一個類不知道它所必須創建的對象的類的時候。
3、當一個類希望由它的子類來指定它所創建的對象的時候。
4、客戶程序使用的對象存在變動的可能,或者根本就不知道使用哪一個具體的對象。
場景4、隨着汽車行業的蓬勃發展,競爭也越來越激烈,為了在競爭中生存,廠長決定為各個型號的汽車安裝一個智能導航系統,但寶馬只能安裝寶馬導航,奔馳只能安裝奔馳自己的導航。
解決方法:廠長決定把導航儀的生產放到各個汽車工廠一起生產。
具體類如下:
新增一個導航儀的接口和實現類
新增一個抽象工廠和實現類
客戶端類為
這里用到的設計模式是抽象工廠模式:
意圖:為創建一組相關或相互依賴的對象提供一個接口,而且無需指定他們的具體類。
使用場景: 1、當需要創建的對象是一系列相互關聯或相互依賴的產品族時,便可以使用抽象工廠模式。
2、一個系統要由多個產品系列中的一個來配置時。
3、當你要強調一系列相關的產品對象的設計以便進行聯合使用時。
場景5、隨着汽車的組裝越來越復雜,工廠已經不能適應外界快速的變化了,所以廠長決定工廠只是生產汽車需要的部件,由一個專門的工廠負責組裝。通常汽車部件是比較固定的,但組裝流程較易變,把易變的分離出去,把不變的保留,這樣能更好的應對外界的變化。而且,還能使用不同的部件,建造各樣的汽車。
代碼為:
相對於抽象工廠,我們只增加了一個director類,負責汽車制造的復雜邏輯。
客戶端只需要和導演類通信即可。
這里用到的模式為建造者模式
意圖:將一個復雜對象的構建與它的表示分離,使得同樣的構建過程可以創建不同的表示。
總結
上面介紹的幾個模式都是秉承了“把易變的部分抽離出來,並用抽象代替具體實現”,因為具體是易變的,抽象是不變的。所以我們在代碼設計的過程中,如何抽象,如何化易變為不變是很重要的。同時,要記住“最小知道原則”,如果客戶端知道的越多,那代碼的約束越多,面對變化的能力也越弱。
參考文獻
設計模式(一)工廠模式Factory(創建型)
《設計模式-可復用面向對象軟件的基礎》