由浅到深了解工厂模式
作者 點先生 日期 2018.9.26
嘮個嗑
先給各位觀眾老爺道個歉,在上一篇文章的末尾本來說了這次要給大家分享代理模式,但是臣妾,做不到啊! 最近公司給我了一個新項目,于是比較忙一點,再加上代理模式那邊的東西有點多,我有點懵逼的,靜態、動態、遠程、虛擬,還有個RMI,小機靈鬼兒的腦袋一時間處理不過來啊!
最近在搭建新項目的時候,參考了前輩的一些代碼。這一次看別人代碼的時候,更容易知道別人寫著類的目的是干嘛,為啥要這樣寫了,這就是學習設計模式之后的好處之一吧,我仍然會繼續加油。嘗到了一些甜頭,現在更有動力了。你們的留言,討論,點贊更是我巨大的動力。雖然是中途改道來寫工廠模式,但絕對不會讓各位觀眾老爺失望的!本次要講的是三種工廠模式(簡單工廠模式,工廠方法模式,抽象工廠模式),以及相關模式源碼上的一些理解、擴展。
什么是工廠模式
new!
準確的說,是代替new實例化具體類的一種模式。 接下來我將以“音樂廠牌創造音樂”為例子,由淺到深深入工廠模式。
至于為什么要用工廠模式我會邊講例子邊說。
簡單工廠模式
制作一首歌曲,確定歌曲風格之后,就先要寫詞譜曲,然后依次就是錄歌,剪輯,混音,就可以發型了。當然也可以“不混,直接發”!Skr~。
public class MusicLabel {Song createSong(String type){Song song = null;if(type.equals("folk")){ song = new FolkSong();}else if(type.equals("rock")){song = new RockSong();}else if(type.equals("pop")){song = new PopSong();}song.prepare();//作詞作曲演奏song.Sing(); //錄歌song.Cut(); //剪輯song.Mix(); //混音return song;} } 復制代碼這樣寫,有沒有問題? 沒有! 不出bug能跑就完事兒了。科科。
然而這樣卻違反了開閉原則:對擴展開放,對修改關閉。
我們可以把易變化的部分跟不變化的部分分開。也就是將new對象的部分提出來,單獨形成一個類(工廠)。
在這兒有另外一種方法:利用靜態方法定義一個簡單工廠(靜態工廠)。
這樣就不需要使用創建對象的方法來實例化對象。但這樣也有一個缺點:不能通過繼承來改變創建方法的行為。
修改之后重寫MusicLabel類
public class MusicLabel {SongFactory factory;public MusicLabel(SongFactory factory) {this.factory = factory;}Song createSong(String type){Song song = null;song = factory.orderSong(type);song.prepare();song.Sing();song.Cut();song.Mix();return song;} } 復制代碼這樣一來就將面向具體編程,變成了面向接口編程。
在設計模式中,“實現一個接口”泛指“實現某個超類型(類/接口)的某個方法”。
心得
給我的感覺,簡單工廠模式更像是一種編程的習慣。最簡單的解耦,使得工廠類能夠被各種廠牌反復使用。
在我還沒認識簡單工廠之前,其實我就寫過很多簡單工廠的例子了。各種基類BaseActivity、BaseFragment等等通常都會用到簡單工廠模式。
優點: 簡單,解耦。
缺點: 靜態工廠無法繼承,違反開閉原則。
工廠方法模式
定義
工廠方法模式定義了一個創建對象的接口,但由子類決定要實例化的類是哪一個。工廠方法讓類把實例化推遲到子類。
類圖
工廠方法模式有四個核心類:
來擼代碼
剛剛我們已經創建了兩個類,MusicLabel和SongFactory,MusicLabel在工廠方法中可以作為一個Creator。SongFactory不在四大核心之內,先不管。
我們先來創造一下產品類和創建者類(他們是兩個平行類層級)。
接下來創建各自的子類。廠牌方面,各位最熟知的可能就是“摩登天空”了,另外,聽國搖的小伙伴對謝天笑這個名字應該不會陌生,謝天笑是在“十三月”音樂廠牌。這里我們就以這兩個廠牌為例,來寫各自的子類。
摩登天空音樂廠牌
public class MDSkyMusicLabel extends MusicLabel {@OverrideSong orderSong(String type) { //此處可用簡單工廠模式if(type.equals("folk")){return new MDSkyFolkSong();}else if(type.equals("rock")){return new MDSkyRockSong();}else if(type.equals("pop")){return new MDSkyPopSong();}else return null;} } 復制代碼十三月音樂廠牌
public class ThirteenMonthMusicLabel extends MusicLabel {@OverrideSong orderSong(String type) { //此處可用簡單工廠模式if(type.equals("folk")){return new ThirteenMonthFolkSong();}else if(type.equals("rock")){return new ThirteenMonthRockSong();}else if(type.equals("pop")){return new ThirteenMonthPopSong();}else return null;} } 復制代碼在MusicLabel類的createSong()中,并不知道真正創建的是哪一個廠牌的音樂。創建具體對象的工作,都在子類中。
接下來的工作就是把剛剛寫過的MDSkyFolkSong等具體子類繼承Song。這里只寫一個。
在這里或許許多小伙伴要說這樣寫會有很多子類,很麻煩。但這樣已經是最優的選擇了。耦合度低,遵守了開閉原則。
感受
工廠方法模式有點像簡單工廠的合集,特別是當只有一個具體工廠類存在時。
簡單工廠可以將對象的創建封裝起來,但是簡單工廠不具備工廠方法的彈性,因為簡單工廠不能變更正在創建的產品。
優點: 在簡單工廠的優點上加上“可以變更正在創建的產品”。
缺點: 子類相當多,不便于管理。
抽象工廠模式
剛剛我們再寫具體廠牌的時候,有提到,可以在具體廠牌類中使用簡單工廠模式。也就是說,我們可以創建MDSkySongFactory和ThirteenMonthSongFactory兩個工廠類。并且這兩個工廠做的事都是一樣的,只是具體東西不一樣而已。
那……
我們是不是可以寫一個工廠超類,把要做的事情寫成抽象方法,再讓子工廠類各自實現呢?
可以的!這就是傳說中的抽象工廠模式。
定義
為創建一組相關或相互依賴的對象提供一個接口,而且無需指定他們的具體類。
類圖
由入門到放棄
剛剛我們說過,我們可以整理一個工廠超類,這個工廠超類,就是AbstractFactory!它在我們這個例子中的作用就是返回一個singer,一個lyricist和一個composer。所以我們可以這樣寫。
public interface SongFactory {public String findSinger();public String findLyricist();public String findComposer(); } 復制代碼然后給每個廠牌都寫一個具體工廠
public class MDskySongFactory implements SongFactory {@Overridepublic String findSinger() {return new MDskySinger();}@Overridepublic String findLyricist() {return new MDskyLyricist();}@Overridepublic String findComposer() {return new MDskyComposer();} } 復制代碼public class ThirteenMonthSongFactory implements SongFactory {@Overridepublic String findSinger() {return new ThirteenMonthSinger();}@Overridepublic String findLyricist() {return new ThirteenMonthLyricist();}@Overridepublic String findComposer() {return new ThirteenMonthComposer();} } 復制代碼還需要重寫一下Song類
public abstract class Song {String singer;//演唱者String lyricist;//作詞人String composer;//作曲人abstract void prepare();//只改變了這個方法String Sing(){return "錄歌";}String Cut(){return "剪切";}String Mix(){return "混音";}@Overridepublic String toString() {return "Song{" +"singer='" + singer + '\'' +", lyricist='" + lyricist + '\'' +", composer='" + composer + '\'' +'}';} } 復制代碼現在就可以根據工廠類來寫歌曲子類了。每個廠牌都有FolkSong、RockSong、PopSong,現在不用寫那么多子類,只需要建立一個相應子類,材料(作詞作曲演唱)就交給傳遞進去的工廠類來解決!
public class FolkSong extends Song{SongFactory factory;public FolkSong(SongFactory factory) {this.factory = factory;}@Overridevoid prepare() {singer = factory.findSinger();lyricist = factory.findLyricist();composer = factory.findComposer();} } 復制代碼現在我們幾乎完成了所有的材料,就差調用了。現在先來理一理這些東西。
現在就在Client里面調用看看吧。
public class MDSkyMusicLabel extends MusicLabel {@OverrideSong orderSong(String type) {Song song = null;SongFactory factory = new MDskySongFactory();if(type.equals("folk")){song = new FolkSong(factory);}else if(type.equals("rock")){song = new RockSong(factory);}else if(type.equals("pop")){song = new PopSong(factory);}return song;} } 復制代碼完美!到處都充斥著依賴倒置的清香。
體會
這個模式雖然需要些的核心類比較多,但是當需求滿足“為相互依賴的對象提供一個接口”,具體對象又比較多,又易修改的時候,這個模式的優點你就能體會到了。
優點: 閉合開閉原則,耦合低。
缺點: 不適用于對象數量少的情況。
BitmapFactory
BitmapFactory是android中比較常見的工廠模式的使用。我們肯定都寫過這樣一句代碼 Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher) ; 復制代碼看出來什么沒??
這特么就是個簡單工廠模式啊!還是個靜態工廠!
為何這么說,因為它是通過類名調用方法,并且返回了一個對象。這不就是簡單工廠嗎?
今天的源碼解讀就到此為止了,要問我為啥沒寫擴展。
你要是看懂了工廠模式,就不會問這個問題。
為什么要用工廠模式
(此處應有彈幕:“收尾呼應,滿分作文!”)
我寫的優點里面那么多,還不能讓你使用工廠模式嗎?
就沖解耦合這一點,你就該用它!
總結
以下是我“設計模式系列”文章,歡迎大家關注留言投幣丟香蕉。
設計模式入門
Java與Kotlin的單例模式
Kotlin的裝飾者模式與源碼擴展
由淺到深了解工廠模式
總結
以上是生活随笔為你收集整理的由浅到深了解工厂模式的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 配置连接池druid
- 下一篇: 微服务架构详谈