只有光頭才能變強html
回顧前面:設計模式
工廠模式我我的認爲其實比較難理解的,若是有接觸過|聽過|見過該模式的同窗極可能就會想:我本身new一個對象出來就行了,簡單快捷。用得着你這個工廠模式嗎?搞一個工廠出來還要寫一大堆的代碼呢~微信
網上的不少資料都是在闡述着:工廠模式的好處就是解耦。相信你們對解耦這個詞也不陌生,那解耦究竟有什麼好處呢?iphone
本文章試圖去解釋爲何要用工廠模式,用了工廠模式的好處是什麼,以及工廠模式衍生出的三種形式究竟有什麼區別~~ide
那麼接下來就開始吧,若是有錯的地方但願能多多包涵,並不吝在評論區指正!post
在《設計模式之禪》這本書中分了兩章節講工廠模式:.net
抽象工廠模式
網上的大部分資料都是將工廠模式分紅三種:設計
想一想咱們爲何要用工廠模式?下面我就簡單舉例子:代理
文件IO的操做咱們會常常用獲得吧,因此BufferedReader對象常常要建立的:code
// 建立一個BufferedReader對象 BufferedReader bf = new BufferedReader(new FileReader(new File("aa.txt")));
你說麻煩嗎?其實也不麻煩,就一行代碼嘛,哪裏麻煩了~若是不太熟悉IO流的同窗就沒有那麼機靈了,建立一個BufferedReader可能就是如下的代碼了:
File file = new File("aa.txt"); FileReader fileReader = new FileReader(file); BufferedReader bufferedReader = new BufferedReader(fileReader);
你說麻煩嗎?其實也不麻煩,不就是三行代碼嘛,哪裏麻煩了~若是這個應用不少的類上都用到了BufferedReader對象的話,那每一個類都寫上這三行代碼了。那你說麻煩嗎?那確定麻煩啊,還用想啊….
能夠看出來,建立一個BufferReader對象裏面須要一個FileReader對象,而FileReader對象又要File對象。那建立這個BufferReader對象仍是比較麻煩的(代碼上看不麻煩,從構造上看仍是挺麻煩的)!
雖然比較麻煩,但咱們還能用,能用就行!因而乎,咱們就去寫代碼了,如今有三個類都要進行文件的讀寫操做,因而他們就有這樣的代碼:
public class FileOperateA { public static void main(String[] args) throws FileNotFoundException { File file = new File("aa.txt"); FileReader fileReader = new FileReader(file); BufferedReader bufferedReader = new BufferedReader(fileReader); // 讀寫文件.... } }
此時:上頭說,我要換成LineNumberReader來讀寫,有這個需求!那咱們做爲一個寫代碼的,能怎麼辦?很絕望也須要去完成呀。
熟悉IDE的小夥子就全局替換重構,妥妥的!
哎,寫個代碼屁事真多…那有沒有一種方法可以讓建立對象變得簡單並且修改對象時能很方便呢?
哎,工廠模式就好了。
再說從面向對象的角度來看:我一個操做文件的類還要我會建立BufferReader是否是有點過度了?(職責沒有分工好)
何爲工廠?將咱們的產品都交由工廠來生產!我如今用的iphone5s,從哪來?從富士康組裝而來,富士康是工廠。我用得着知道iphone5s在富士康是怎麼組裝起來的嗎?不須要。
來,咱們來改造一下上面的例子。首先咱們建立一個工廠類,它能夠生產Reader對象!
// 建立Reader對象的工廠 public class ReaderFactory { public static Reader getReader() throws FileNotFoundException { File file = new File("aa.txt"); FileReader fileReader = new FileReader(file); BufferedReader reader = new BufferedReader(fileReader); return reader; } }
那麼咱們要獲得BufferReader對象就賊簡單了:
public class FileOperateA { public static void main(String[] args) throws FileNotFoundException { //-------我有工廠了,還用本身搞嗎?不用了! //File file = new File("aa.txt"); //FileReader fileReader = new FileReader(file); //BufferedReader bufferedReader = new BufferedReader(fileReader); //-------我有工廠了,還用本身搞嗎?不用了! // 用工廠來建立出對象 Reader reader = ReaderFactory.getReader(); // 讀寫文件.... } }
工廠將咱們建立的對象過程給屏蔽了!
此時我要改爲LineNumberReader怎麼玩?在工廠上改一下就行了:
咱們的調用方FileOperateA|FileOperateB|FileOperateC這些類徹底就不用變!
從上面的工廠模式體驗咱們就能夠看到:
我再放下我以前練習的時候寫過的代碼吧:
我有一個DaoFactory,邏輯很簡單就是專門建立Dao對象的~
那麼在Service層就可使用工廠將想要的Dao對象初始化了~
此時咱們的Service與Dao的對象低耦合的~
在一開始我就說了,工廠模式能夠分紅三類:
三種模式都以:Java3y要買寵物的例子來說解~
不少博客都是以簡單/靜態工廠模式,工廠方法模式,抽象工廠模式這個順序來說解工廠模式的。我認爲按書上的順序比較好理解~由於簡單/靜態工廠模式是在工廠方法模式上縮減,抽象工廠模式是在工廠方法模式上再加強。
做爲一間寵物店,號稱什麼寵物都有!因而乎,店主宣傳的時候就說:個人寵物店什麼寵物都有!
因而構建寵物的工廠就誕生了~
// 號稱什麼寵物都有 public interface AnimalFactory { // 能夠獲取任何的寵物 Animal createAnimal(); }
固然了,主流的寵物得進貨一些先放在店裏充充門面,一些特殊的寵物就告訴顧客要時間進貨~
// 繼承着寵物工廠 public class CatFactory implements AnimalFactory { @Override // 建立貓 public Animal createAnimal() { return new Cat(); } }
狗工廠也是同樣的:
// 繼承着寵物工廠 public class DogFactory implements AnimalFactory { // 建立狗 @Override public Animal createAnimal() { return new Dog(); } }
嗯,還有咱們的實體類:貓、狗、動物(多態:貓和狗都是動物,能夠直接用動物來表示了)
動物實體類:
public abstract class Animal { // 全部的動物都會吃東西 public abstract void eat(); }
貓實體類:
public class Cat extends Animal { // 貓喜歡吃魚 @Override public void eat() { System.out.println("貓吃魚"); } }
狗實體類:
public class Dog extends Animal { // 狗喜歡吃肉 @Override public void eat() { System.out.println("狗吃肉"); } }
那麼如今Java3y想要一隻狗,跟了寵物店老闆說,寵物店老闆就去找狗回來了:
// 去找狗工廠拿一隻狗過來 AnimalFactory f = new DogFactory(); // 店主就拿到了一隻狗給Java3y Animal a = f.createAnimal(); a.eat(); System.out.println("關注公衆號:Java3y");
那麼如今Java3y想要一隻貓,跟了寵物店老闆說,寵物店老闆就去找貓回來了:
// 去找貓工廠拿一隻貓過來 AnimalFactory ff = new CatFactory(); // 店主就拿到了一隻貓給Java3y Animal aa = ff.createAnimal(); aa.eat(); System.out.println("關注公衆號:Java3y");
若是這個時候Java3y說想要一隻蜥蜴怎麼辦啊?沒問題啊,店主搞個蜥蜴工廠就行了~~
// 要買蜥蜴.. AnimalFactory fff = new LizardFactory(); Animal aaa = ff.createAnimal(); aaa.eat();
優勢:
3:不會影響已有的代碼,後期維護容易,加強系統的擴展性
缺點:
如今寵物店生意很差作啊,號稱「什麼寵物都有",這吹過頭了~~因而店主只賣兩種常見的寵物了。
public class AnimalFactory { public static Dog createDog() { return new Dog(); } public static Cat createCat() { return new Cat(); } // 外界想要貓要狗,這裏建立就行了 public static Animal createAnimal(String type) { if ("dog".equals(type)) { return new Dog(); } else if ("cat".equals(type)) { return new Cat(); } else { return null; } } }
三個實體仍是沒變(動物、貓、狗)….
那麼Java3y去寵物店買貓狗的時候,告訴老闆我要貓、我要狗:
// 拿到狗 Animal A = AnimalFactory.createAnimal("dog"); A.eat(); // 拿到貓 Animal C = AnimalFactory.createAnimal("cat"); C.eat();
如今問題來了:
抽象工廠模式就比較複雜了,咱們通常的應用都寫不到。我首先來簡述一下需求吧:
有的喜歡母的
那咱們的貓和狗都是有性別的,不是公的就是母的~~
咱們的最大工廠仍是定義了建立什麼動物
public interface AnimalFactory { Animal createDog(); Animal createCat(); }
建立母貓和母狗的工廠:
public class FemaleAnimalFactory implements AnimalFactory { // 生產母狗和母貓 @Override public Animal createDog() { return new FemaleDog(); } @Override public Animal createCat() { return new FemaleCat(); } }
建立公貓和公狗的工廠:
public class MaleAnimalFactory implements AnimalFactory { // 生產公狗和公貓 @Override public Animal createDog() { return new MaleDog(); } @Override public Animal createCat() { return new MaleCat(); } }
這是全部動物都擁有的廣泛行爲:
public abstract class Animal { // 全部的動物都會吃東西 public abstract void eat(); // 全部的動物都有性別 public abstract void gender(); }
這是貓都擁有的廣泛行爲:
public abstract class Cat extends Animal { // 貓喜歡吃魚 @Override public void eat() { System.out.println("貓吃魚"); } }
這是狗都擁有的廣泛行爲:
public abstract class Dog extends Animal { // 狗喜歡吃肉 @Override public void eat() { System.out.println("狗吃肉"); } }
貓分爲公貓、母貓。狗分爲公狗和母狗:
public class FemaleCat extends Cat { public void gender() { System.out.println("I am a female Cat"); } } …..
簡單來講:工廠方法模式的工廠是建立出一種產品,而抽象工廠是建立出一類產品。
public static void main(String[] args) { // 須要性別爲母的就去找母工廠 AnimalFactory af = new FemaleAnimalFactory(); // 須要一隻母貓 af.createCat().gender(); // 須要一隻母狗 af.createDog().gender(); System.out.println("-------------關注公衆號:Java3y-------------------------"); // 須要性別爲公的就去找公工廠 AnimalFactory aff = new MaleAnimalFactory(); // 須要一隻公狗 aff.createDog().gender(); // 須要一隻公貓 aff.createCat().gender(); }
效果:
這是抽象工廠模式的類圖:
抽象工廠模式說到底就是多了一層抽象,減小了工廠的數量。
抽象工廠缺點也很明顯:
總的來講咱們用簡單工廠模式比較多,工廠方式模式的話代碼量會比較大,抽象工廠模式的話須要業務比較大的狀況下才會用到(若是有更好的理解方式不妨在評論區留言,一塊兒交流交流漲漲見識~~)
工廠模式配合反射來使用也是極好的~
參考資料:
若是文章有錯的地方歡迎指正,你們互相交流。習慣在微信看技術文章,想要獲取更多的Java資源的同窗,能夠關注微信公衆號:Java3y。爲了你們方便,剛新建了一下qq羣:742919422,你們也能夠去交流交流。謝謝支持了!但願能多介紹給其餘有須要的朋友
文章的目錄導航: