工廠模式(簡單、普通、抽象)
概述
屬於建立型設計模式,需要生成的物件叫做產品 ,生成物件的地方叫做工廠 。
使用場景:
1、在任何需要生成複雜物件的地方,都可以使用工廠方法模式。
2、直接用new可以完成的不需要用工廠模式
一、簡單(靜態)工廠
我喜歡吃粉,抽象一個粉基類(或者介面),這是產品的抽象類
package com.wbg.FactoryMode; public abstract class Powder { /** * 描述粉 * 桂林米粉、柳州螺螄粉 */ public abstract void desc(); }
來一份桂林米粉(具體的產品類)
package com.wbg.FactoryMode; public class GlPowder extends Powder { @Override public void desc() { System.out.println("桂林米粉,很好吃,上海的很貴,在家才5-6塊錢"); } }
我老家的螺螄粉(具體的產品類)
package com.wbg.FactoryMode; public class LsfPowder extends Powder { @Overridepublic void desc() { System.out.println("螺螄粉,不錯,老家6塊錢,珠海10多塊"); } }
準備工作做完了,我們來到一家“粉店”(簡單工廠類),選單如下:
package com.wbg.FactoryMode; public class SimplePowderFactor { public static final int TYPE_LZ = 1;//桂林米粉 public static final int TYPE_PM = 2;//螺螄粉 public static Powder createNoodles(inttype) { if(type==1){ return new GlPowder(); }else { return new LsfPowder(); } } }
簡單粉店就提供二種麵條(產品),你說你要啥,他就給你啥。這裡我點了桂林米粉:
package com.wbg.FactoryMode;
/**
* 簡單工廠模式
*/ public class Customer { public static void main(String[] args) { Powder powder=SimplePowderFactor.createNoodles(SimplePowderFactor.TYPE_LZ); powder.desc(); } }
特點
1、 它是一個具體的類,非介面 抽象類。有一個重要的create()方法,利用if或者 switch建立產品並返回。
2、 create()方法通常是靜態的,所以也稱之為靜態工廠。
缺點
1、 擴充套件性差(我想增加一種粉,除了新增一個粉產品類,還需要修改工廠類方法)
2 、不同的產品需要不同額外引數的時候 不支援。
二、另一種簡單工廠(反射):
利用反射Class.forName(
tClass.getName()).newInstance()
實現的簡單工廠:
package com.wbg.FactoryMode; public class StaticPowderFactor { /** * 傳入Class例項化粉產品類 * * @param tClass * @param <T> * @return */ public static <T extends Powder>T createPowder(Class<T> tClass){ T result=null; try { result= (T) Class.forName(tClass.getName()).newInstance(); }catch (Exception e){ System.out.println(e.getMessage()); } return result; } }
點粉:
package com.wbg.FactoryMode; public class Customer { public static void main(String[] args) { Powder powder=StaticPowderFactor.createPowder(new LsfPowder().getClass()); powder.desc(); } }
特點
1 它也是一個具體的類,非介面 抽象類。但它的create()方法,是利用反射機制生成物件返回,好處是增加一種產品時,不需要修改create()的程式碼。
缺點
1 因為Class.forName(clz.getName()).newInstance()呼叫的是無參建構函式生成物件,它和new Object()是一樣的性質,而工廠方法應該用於複雜物件的初始化 ,當需要呼叫有參的建構函式時便無能為力了,這樣像為了工廠而工廠。
2 不同的產品需要不同額外引數的時候 不支援。
三、多方法工廠
上面都有一個缺點:不同的產品需要不同額外引數的時候 不支援。
如果使用時傳遞的type、Class出錯,將不能得到正確的物件,容錯率不高。
多方法的工廠模式為不同產品,提供不同的生產方法,使用時 需要哪種產品就呼叫該種產品的方法,使用方便、容錯率高。
工廠:
package com.wbg.FactoryMode; public class VariedPowderFactor { /** * 生產桂林米粉 * @return */ public static Powder createGl(){ return new GlPowder(); } /** * 生產螺絲粉 * @return */ public static Powder createLsf(){ return new LsfPowder(); } }
點餐:
package com.wbg.FactoryMode; public class Customer { public static void main(String[] args) { Powder glpowder=VariedPowderFactor.createGl(); glpowder.desc(); Powder lsfpowder=VariedPowderFactor.createLsf(); lsfpowder.desc(); } }
四、普通工廠
普通工廠就是把簡單工廠中具體的工廠類,劃分成兩層:抽象工廠層+具體的工廠子類層。(一般->特殊)
工廠(抽象工廠類),作用就是生產粉:
package com.wbg.FactoryMode; public abstract class PowderFactory { public abstract Powder create(); }
我老家的螺螄粉(具體工廠子類):
package com.wbg.FactoryMode; public class createLsfFactory extends PowderFactory { @Override public Powder create() { return new LsfPowder(); } }
桂林米粉(具體工廠子類):
package com.wbg.FactoryMode; public class createGlFactory extends PowderFactory{ @Override public Powder create() { return new GlPowder(); } }
使用:
package com.wbg.FactoryMode; public class Customer { public static void main(String[] args) { PowderFactory factory=new createGlFactory(); Powder powder=factory.create(); powder.desc(); } }
普通工廠與簡單工廠模式的區別:
可以看出,普通工廠模式特點:不僅僅做出來的產品要抽象, 工廠也應該需要抽象。
工廠方法使一個產品類的例項化延遲到其具體工廠子類.
工廠方法的好處就是更擁抱變化。當需求變化,只需要增刪相應的類,不需要修改已有的類。
簡單工廠需要修改工廠類的create()方法,多方法靜態工廠模式需要增加一個靜態方法。
缺點:
引入抽象工廠層後,每次新增一個具體產品類,也要同時新增一個具體工廠類!
抽象工廠
以上介紹的工廠都是單產品系的。抽象工廠是多產品系 。
每個粉店(工廠)不僅僅賣粉,還提供飲料賣。
提供飲料賣,飲料是產品,先抽象一個產品類,飲料:
public abstract class IDrinks { /** * 描述每種飲料多少錢 */ public abstract void prices(); }
可樂:
public class ColaDrinks extends IDrinks { @Override public void prices() { System.out.println("可樂1塊錢"); } }
水:
public class WaterDrinks extends IDrinks { @Override public void prices() { System.out.println("太辣了,我要和免費水"); } }
抽象粉店(抽象工廠類):
public abstract class AbstractFoodFactory { /** * 生產麵條 * * @return */ public abstract Powder createPowder(); /** * 生產飲料 */ public abstract IDrinks createDrinks(); }
柳州螺螄粉(具體工廠類):
public class LsflmFoodFactory extends AbstractFoodFactory { @Override public Powder createPowder() { return new LsfPowder();//螺螄粉 } @Override public IDrinks createDrinks() { return new WaterDrinks();//賣水 } }
酒店(具體工廠類):
public class hodelFoodFactory extends AbstractFoodFactory { @Override public Powder createPowder() { return new GlPowder();//桂林米粉很好吃,酒店都有了 } @Override public IDrinks createDrinks() { return new ColaDrinks();//賣可樂 } }
使用:
AbstractFoodFactory abstractFoodFactory1 = new hodelFoodFactory(); abstractFoodFactory1.createDrinks().prices(); abstractFoodFactory1.createPowder().desc(); AbstractFoodFactory abstractFoodFactory2 = new LsflmFoodFactory(); abstractFoodFactory2.createDrinks().prices(); abstractFoodFactory2.createPowder().desc()
缺點
將工廠也抽象後,有個顯著問題,就是類爆炸了。而且每次拓展新產品種類,例如不僅賣吃賣喝,我還想賣其他,這需要修改抽象工廠類,因此所有的具體工廠子類,都被牽連,需要同步被修改。