上一篇《Java設計模式之單例模式》詳細介紹了單例模式,介紹了單例模式的使用場景,優缺點,同時也寫了兩種常見的單例模式寫法,懶漢式單例模式和餓漢氏單例模式,固然,單例模式的寫法還有不少,好比,枚舉單例模式,靜態內部類單例模式等。有興趣的能夠自行查找資料。本篇開始介紹單例模式的第二篇,工廠方法模式,以及工廠模式的升級版,抽象工廠模式。java
定義:Define an interface for creating an object,but let subclasses decide which class to instantiation.Factory Mehod lets a class defer instantiation to subclasses.翻譯過來就是,定義一個用於建立對象的接口,讓其子類決定實例化哪一個類。工廠方法讓一個類的實例化延遲到其子類。設計模式
上面的定義說明好像很繞口,若是不理解不要緊,咱們用個例子來講明這個定義:ide
//定義產品接口 public interface Iproduct { public void doSomething(); } //產品實現類 public class ProductA implements Iproduct { @Override public void doSomething() { System.out.println("我是產品A,我能夠搞事情"); } } //定義工廠類接口 public interface IFactory { //建立產品工廠方法 < T extends Iproduct> T creatProduct(Class<T> clz); } //工廠方法實現類 public class ProductFactory implements IFactory { @Override public <T extends Iproduct> T creatProduct(Class<T> clz) { Iproduct product=null; try { product= clz.newInstance(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } return (T) product; } } //場景類 public class Client { public static void main(String[] args) { IFactory factory=new ProductFactory(); Iproduct product= factory.creatProduct(ProductA.class); product.doSomething(); } }
上述例子,實現了一個簡單的工廠方法模式,定義了一個工廠接口類,而後具體的工廠方法實現了建立對象的邏輯。看到這裏,有人確定會問,這裏要new一個工廠類的實例,和我new一個具體的對象有什麼區別呢?反正都要本身new,幹嗎要搞一個工廠類這麼繞呢?對,沒錯。這裏是要new一個工廠類,可是上面的例子建立產品的對象是比較簡單,因此感受不出來,若是ProductA的實例建立是一個很是複雜的過程,那麼這個時候我經過工廠方法模式建立對象的實例就很方便了。post
確定還有人問,我以爲上面這個方式還有點囉嗦,有沒有更簡便的方式實現工廠模式呢?答案是,有。咱們接下來看看簡單工廠模式。簡單工廠方法模式就是上述工廠方法模式的簡單版本。咱們只要把上述工廠類的接口去掉,而後把工廠實現類改成靜態類就能夠實現簡單工廠方法模式了。代碼是這樣的:.net
//這裏只去掉了接口,改成靜態方法 public class ProductFactory { public static <T extends Iproduct> T creatProduct(Class<T> clz) { Iproduct product=null; try { product= clz.newInstance(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } return (T) product; } } public class Client { public static void main(String[] args) { Iproduct product= ProductFactory.creatProduct(ProductA.class); product.doSomething(); } }
這裏就不用本身去new 工廠類啦,代碼也簡潔了不少。可是去掉了接口也就意味着後面的擴展是不友好的,因此違反了開閉原則。翻譯
定義:Provide an interface for creating families of related or dependent objects without specifying their concrete classes.翻譯: 提供一個建立相關或者相互依賴的對象的接口,而且無需指定他們的具體實現類。設計
這裏理解可能有點困難,爲了便於理解,咱們先引入兩個概念。3d
產品等級結構: 產品等級結構即產品的繼承結構,如一個抽象類是汽車,其子類就是各個品牌的汽車,好比奔馳,寶馬汽車。汽車和奔馳就構成了一個產品等級結構,抽象汽車是父類,而具體品牌的汽車是其子類。code
產品族 : 在抽象工廠模式中,產品族是指由同一個工廠生產的,位於不一樣產品等級結構中的一組產品,如奔馳工廠生產的奔馳跑車,寶馬公司生產的跑車,奔馳跑車位於奔馳產品等級結構中,寶馬跑車位於寶馬產品等級結構中。對象
因此,汽車和品牌是一個產品等級結構,而每一個品牌下面有多個產品線,也就是說奔馳牌下面的汽車有多個產品族,好比跑車族,SUV族。奔馳跑車和寶馬跑車是一個產品族,奔馳SUV和寶馬SUV是一個產品族。因此上面定義中「相關或者相互依賴的對象」就是場景中包含,同一個等級結構中有不一樣的產品族。 ,咱們來用一個實際場景來講明下。
假設,我須要一個汽車工廠,汽車能夠生產跑車和SUV車型,那麼這個時候用以前的工廠方法模式就不知足了,方法工廠模式只能知足生產一個產品,如今須要生產兩個產品。因此咱們在方法工廠模式的基礎上改造下來知足這個場景。
//汽車接口 public interface ICar { void dirver(); } //抽象汽車類 public abstract class AbstractProduct implements ICar{ @Override public void dirver() { System.out.println("我是汽車,我能夠開動"); } /*** * 展現不一樣車的亮點*/ public abstract void showSpecial(); } //寶馬SUV實現類 public class BmwSuv extends AbstractProduct { @Override public void showSpecial() { System.out.println("我是寶馬牌SUV,個人特色就是多功能用途"); } } //寶馬跑車實現類 public class BmwProductRoadster extends AbstractProduct { @Override public void showSpecial() { System.out.println("我是寶馬跑車,個人特色就是跑的快"); } } //奔馳SUV public class BenzSuv extends AbstractProduct { @Override public void showSpecial() { System.out.println("我是奔馳牌SUV,個人特色就是多功能用途"); } } //奔馳跑車 public class BenzProductRoadster extends AbstractProduct { @Override public void showSpecial() { System.out.println("我是奔馳跑車,個人特色就是跑的快"); } } //抽象工廠類 public abstract class AbstractFactory { //建立跑車 public abstract < T extends ICar> T createRoadster(); //建立SUV public abstract < T extends ICar> T createSuv(); } //奔馳汽車工廠類 public class BenzFactory extends AbstractFactory { @Override public <T extends ICar> T createRoadster() { return (T) new BenzProductRoadster(); } @Override public <T extends ICar> T createSuv() { return (T) new BenzSuv(); } } //寶馬汽車工廠類 public class BmwFactory extends AbstractFactory { @Override public <T extends ICar> T createRoadster() { return (T) new BmwProductRoadster(); } @Override public <T extends ICar> T createSuv() { return (T) new BmwSuv(); } } //場景類 public class Client { public static void main(String[] args) { AbstractFactory bmwFactory=new BmwFactory(); AbstractFactory benzFactory=new BenzFactory(); AbstractProduct bmwRoadster= bmwFactory.createRoadster(); AbstractProduct bmwSuv=bmwFactory.createSuv(); AbstractProduct benzRoadster=benzFactory.createRoadster(); AbstractProduct benzSuv=benzFactory.createSuv(); bmwRoadster.showSpecial(); bmwSuv.showSpecial(); benzRoadster.showSpecial(); benzSuv.showSpecial(); } }
細心的讀者應該發現,咱們的改造相對於工廠方法模式而言,只是抽象工廠模式新增了多一個建立方法。這也是抽象工廠模式和工廠方法模式最明顯的區別,抽象工廠模式能夠知足多類型,多業務的場景,好比汽車工廠能夠生產多種類型汽車,就適用於抽象工廠模式。而普通工廠方法模式就是針對生產某一種對象而言比較適用。總結來講就是,抽象工廠模式適用於多產品族的狀況,普通工廠方法模式適用於單產品族狀況。
上面介紹了工廠方法模式與抽象工廠模式的定義與實踐,同時也衍生了一個簡單工廠模式。咱們先來總結下工廠模式的優勢與缺點。
優勢:
1.良好的封裝性,代碼結構清晰,不用關注具體對象的建立過程,符合迪米特法則。
2.良好的擴展性,咱們擴展了產品,只要新建對應的工廠類,實現本身的實現邏輯便可。
缺點:
1.對於抽象工廠模式,產品族的擴展比較困難,須要修改頂部抽象工廠類,這會致使全部實現類都要修改,不符合開閉原則。
2.對於簡單工廠模式,因爲沒有接口和抽象父類的約束,從而也會致使擴展只能修改代碼,不符合開閉原則。
最後咱們列一個表格來總結下工廠方法模式,簡單工廠模式,抽象工廠模式的區別。
簡單工廠模式 | 工廠方法模式 | 抽象工廠模式 | |
---|---|---|---|
有無接口或抽象類 | 無 | 有 | 有 |
適用場景 | 通常不涉及擴展,單產品族 | 涉及單產品族,便於擴展 | 多產品族場景,能夠擴展等級結構,不便於擴展產品族 |
實現複雜度 | 最簡單 | 簡單 | 通常 |
《設計模式之禪》