概述
属于创建型设计模式,需要生成的对象叫做产品 ,生成对象的地方叫做工厂 。
使用场景:
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 { @Override public 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(int type) { 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()
缺点
将工厂也抽象后,有个显著问题,就是类爆炸了。而且每次拓展新产品种类,例如不仅卖吃卖喝,我还想卖其他,这需要修改抽象工厂类,因此所有的具体工厂子类,都被牵连,需要同步被修改。