先来一个生动的例子:
大众汽车的MQB平台是现在非常出名的横置发动机模块化生产平台,从这个平台上出生了许多的广为人知的汽车型号,如奥迪TT、大众Polo、高尔夫等等。抽象化思考,这些汽车都出自一个生产平台,而不是每辆车都单独占有一个平台,那么问题来了,如何让一个平台生产出多个型号的汽车呢?
我们以上述三种车型为例,先定义出三种车的类
public class AudiTT { public void run() { System.out.println("AudiTT run..."); } } public class Polo { public void run() { System.out.println("Polo run..."); } } public class Golf { public void run() { System.out.println("Golf run..."); } }
如何让平台生产三种型号的车型呢?有同学就会提出这样的做法,让平台实现每个型号的生产方法不就行了,于是乎有了下面的代码
public class Factory { public AudiTT produceAudiTT() { return new AudiTT(); } public Polo producePolo() { return new Polo(); } public Golf produceGolf() { return new Golf(); } }
写个场景类测试一下
public class Test { public static void main(String[] args) { Factory factory = new Factory(); AudiTT audiTT = factory.produceAudiTT(); Polo polo = factory.producePolo(); audiTT.run(); polo.run(); } }
输出结果
AudiTT run...
Polo run...
这么做看起来似乎是可行的,但是我们注意到,这个工厂类实际上没有一点作用,相当于我们自己new了一个具体的汽车对象,在接收工厂生产出的对象时,也不能用统一的类去接收,且我们每增加一个汽车类,就需要修改工厂类,工厂类和汽车类之间耦合性极强,增加出错风险,代码的复用性也不高,这是不符合设计原则的。
为了增强类间解耦合,我们引入抽象类,定义产品的公共行为,此例中就是run()方法,我们定义Car类为汽车类的公共父类
public abstract class Car { public abstract void run(); }
此时,三个汽车类相应继承Car类,并重写run()方法
public class AudiTT extends Car{ @Override public void run() { System.out.println("AudiTT run..."); } } public class Polo extends Car { @Override public void run() { System.out.println("Polo run..."); } } public class Golf extends Car{ @Override public void run() { System.out.println("Golf run..."); } }
此时,工厂类却可以发生重大变化,我们引入抽象工厂类
public abstract class AbsFactory { public abstract <T extends Car> T produce(Class<T> clazz); }
引入具体工厂类继承抽象工厂,重写生产方法
public class Factory extends AbsFactory{ @Override public <T extends Car> T produce(Class<T> clazz) { Car car = null; try { car = (Car)Class.forName(clazz.getName()).getDeclaredConstructor().newInstance(); }catch (Exception e) { e.printStackTrace(); } return (T)car; } }
写一个场景类进行实验
public class Test { public static void main(String[] args) { AbsFactory factory = new Factory(); Car audiTT = factory.produce(AudiTT.class); Car polo = factory.produce(Polo.class); audiTT.run(); polo.run(); } }
输出结果:
AudiTT run...
Polo run...
现在,我们每增加一个汽车类,再也不用修改工厂类,只要传入具体的类对象信息,工厂类都可以按要求生产对应的汽车对象,实现了汽车类和工厂类解耦合,增加了代码复用度。
我们注意到,在测试类中,我们都是用父类对象去接收子类对象,这在Java中是可行的,利用了Java中子类的向上转型,实现接收变量的统一化,还有就是具体工厂类中,利用了Java的反射功能。
还可以在抽象产品类中加入所有具体产品类的共有属性和方法,进行扩展,同时,抽象工厂类也可以有多个不同的子类,以实现多个生产不同产品,比如汽车工厂、电脑工厂等等不同性质的产品工厂,进行扩展。
优点:
使一个类的实例化延迟到子类,实现类间解耦,屏蔽产品类,增强代码复用度。
具体案例
如果使用JDBC链接数据库,数据库从MySQL变换到Oracle,唯一需要做的就是改变驱动名称,其他都不需要修改
通用模版
我们很容易从上述代码中提取出通用模版
抽象产品类
public abstract class AbsProduct { //产品类的公共方法 public void method1() { } //具体产品类的具体方法,留给子类具体实现 public abstract void method2(); }
具体产品类
public class ConcreteProduct extends AbsProduct { @Override public void method2() { } }
具体产品类可以有多个,越多越能体现工厂模式的优点
抽象工厂类
public abstract class AbsFactory { public abstract <T extends AbsProduct> T produce(Class<T> c); }
具体工厂类
public class ConcreteFactory extends AbsFactory { @Override public <T extends AbsProduct> T produce(Class<T> c) { AbsProduct product = null; try { product = (AbsProduct) Class.forName(c.getName()).getDeclaredConstructor().newInstance(); }catch (Exception e) { e.printStackTrace(); } return (T) product; } }
这只是普通工厂模式的简要介绍,更工厂的抽象工厂模式,留作下一篇总结