做者 點先生 日期 2018.9.26android
先給各位觀衆老爺道個歉,在上一篇文章的末尾原本說了此次要給你們分享代理模式,可是臣妾,作不到啊! 最近公司給我了一個新項目,因而比較忙一點,再加上代理模式那邊的東西有點多,我有點懵逼的,靜態、動態、遠程、虛擬,還有個RMI,小機靈鬼兒的腦殼一時間處理不過來啊! 編程
最近在搭建新項目的時候,參考了前輩的一些代碼。這一次看別人代碼的時候,更容易知作別人寫着類的目的是幹嗎,爲啥要這樣寫了,這就是學習設計模式以後的好處之一吧,我仍然會繼續加油。嚐到了一些甜頭,如今更有動力了。大家的留言,討論,點贊更是我巨大的動力。雖然是中途改道來寫工廠模式,但絕對不會讓各位觀衆老爺失望的!本次要講的是三種工廠模式(簡單工廠模式,工廠方法模式,抽象工廠模式),以及相關模式源碼上的一些理解、擴展。設計模式
new!
準確的說,是代替new實例化具體類的一種模式。 接下來我將以「音樂廠牌創造音樂」爲例子,由淺到深深刻工廠模式。
至於爲何要用工廠模式我會邊講例子邊說。bash
製做一首歌曲,肯定歌曲風格以後,就先要寫詞譜曲,而後依次就是錄歌,剪輯,混音,就能夠髮型了。固然也能夠「不混,直接發」!Skr~。composer
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對象的部分提出來,單獨造成一個類(工廠)。ide
public class SongFactory {
public Song orderSong(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();
}
return song;
}
}
複製代碼
在這兒有另一種方法:利用靜態方法定義一個簡單工廠(靜態工廠)。
這樣就不須要使用建立對象的方法來實例化對象。但這樣也有一個缺點:不能經過繼承來改變建立方法的行爲。post
修改以後重寫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;
}
}
複製代碼
這樣一來就將面向具體編程,變成了面向接口編程。ui
在設計模式中,「實現一個接口」泛指「實現某個超類型(類/接口)的某個方法」。this
給個人感受,簡單工廠模式更像是一種編程的習慣。最簡單的解耦,使得工廠類可以被各類廠牌反覆使用。
在我還沒認識簡單工廠以前,其實我就寫過不少簡單工廠的例子了。各類基類BaseActivity、BaseFragment等等一般都會用到簡單工廠模式。
優勢: 簡單,解耦。
缺點: 靜態工廠沒法繼承,違反開閉原則。
工廠方法模式定義了一個建立對象的接口,但由子類決定要實例化的類是哪個。工廠方法讓類把實例化推遲到子類。
工廠方法模式有四個核心類:
剛剛咱們已經建立了兩個類,MusicLabel和SongFactory,MusicLabel在工廠方法中能夠做爲一個Creator。SongFactory不在四大核心以內,先無論。
咱們先來創造一下產品類和建立者類(他們是兩個平行類層級)。
public abstract class MusicLabel {
Song createSong(String type){
Song song = null;
song = orderSong(type);
song.prepare();
song.Sing();
song.Cut();
song.Mix();
return song;
}
abstract Song orderSong(String type); //工廠方法
}
複製代碼
public abstract class Song {
String singer;//演唱者
String lyricist;//做詞人
String composer;//做曲人
String prepare() {
return "演唱者:"+singer + ",做詞人:"+lyricist + ",做曲人:"+composer;
}
String Sing(){
return "錄歌";
}
String Cut(){
return "剪切";
}
String Mix(){
return "混音";
}
}
複製代碼
接下來建立各自的子類。廠牌方面,各位最熟知的可能就是「摩登天空」了,另外,聽國搖的小夥伴對謝天笑這個名字應該不會陌生,謝天笑是在「十三月」音樂廠牌。這裏咱們就以這兩個廠牌爲例,來寫各自的子類。
摩登天空音樂廠牌
public class MDSkyMusicLabel extends MusicLabel {
@Override
Song 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 {
@Override
Song 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。這裏只寫一個。
public class MDSkyFolkSong extends Song {
public MDSkyFolkSong() {
singer = "摩登天空的民謠藝人";
lyricist = "摩登天空的民謠做詞人";
composer = "摩登天空的民謠做曲人";
}
}
複製代碼
在這裏或許許多小夥伴要說這樣寫會有不少子類,很麻煩。但這樣已是最優的選擇了。耦合度低,遵照了開閉原則。
工廠方法模式有點像簡單工廠的合集,特別是當只有一個具體工廠類存在時。
簡單工廠能夠將對象的建立封裝起來,可是簡單工廠不具有工廠方法的彈性,由於簡單工廠不能變動正在建立的產品。
優勢: 在簡單工廠的優勢上加上「能夠變動正在建立的產品」。
缺點: 子類至關多,不便於管理。
剛剛咱們再寫具體廠牌的時候,有提到,能夠在具體廠牌類中使用簡單工廠模式。也就是說,咱們能夠建立MDSkySongFactory和ThirteenMonthSongFactory兩個工廠類。而且這兩個工廠作的事都是同樣的,只是具體東西不同而已。
那……
咱們是否是能夠寫一個工廠超類,把要作的事情寫成抽象方法,再讓子工廠類各自實現呢?
能夠的!這就是傳說中的抽象工廠模式。
爲建立一組相關或相互依賴的對象提供一個接口,並且無需指定他們的具體類。
剛剛咱們說過,咱們能夠整理一個工廠超類,這個工廠超類,就是AbstractFactory!它在咱們這個例子中的做用就是返回一個singer,一個lyricist和一個composer。因此咱們能夠這樣寫。
public interface SongFactory {
public String findSinger();
public String findLyricist();
public String findComposer();
}
複製代碼
而後給每一個廠牌都寫一個具體工廠
public class MDskySongFactory implements SongFactory {
@Override
public String findSinger() {
return new MDskySinger();
}
@Override
public String findLyricist() {
return new MDskyLyricist();
}
@Override
public String findComposer() {
return new MDskyComposer();
}
}
複製代碼
public class ThirteenMonthSongFactory implements SongFactory {
@Override
public String findSinger() {
return new ThirteenMonthSinger();
}
@Override
public String findLyricist() {
return new ThirteenMonthLyricist();
}
@Override
public 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 "混音";
}
@Override
public 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;
}
@Override
void prepare() {
singer = factory.findSinger();
lyricist = factory.findLyricist();
composer = factory.findComposer();
}
}
複製代碼
如今咱們幾乎完成了全部的材料,就差調用了。如今先來理一理這些東西。
如今就在Client裏面調用看看吧。
public class MDSkyMusicLabel extends MusicLabel {
@Override
Song 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;
}
}
複製代碼
完美!處處都充斥着依賴倒置的清香。
這個模式雖然須要些的核心類比較多,可是當需求知足「爲相互依賴的對象提供一個接口」,具體對象又比較多,又易修改的時候,這個模式的優勢你就能體會到了。
優勢: 閉合開閉原則,耦合低。
缺點: 不適用於對象數量少的狀況。
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher) ;
複製代碼
看出來什麼沒??
這特麼就是個簡單工廠模式啊!仍是個靜態工廠!
爲什麼這麼說,由於它是經過類名調用方法,而且返回了一個對象。這不就是簡單工廠嗎?
(此處應有彈幕:「收尾呼應,滿分做文!」)
我寫的優勢裏面那麼多,還不能讓你使用工廠模式嗎?
就衝解耦合這一點,你就該用它!
如下是我「設計模式系列」文章,歡迎你們關注留言投幣丟香蕉。