工厂方法模式 名字 跟已经介绍的 简单工厂模式很类似.
实际上它们的模型也是十分相似的.
我们先看看工厂模式的定义.
一. 工厂方法(Factory Method)模式定义
教材上是这样写的:
工厂方法模式(Factory Method):
定义1个用于创建对象的接口, 让子类决定实例化哪个类. 工厂模式使1个类的实例化延迟到其子类.
是不是觉得定义很恶心, 我也觉得, 刚开始完全看不懂啊.
这里稍稍先分析一下.
定义1个用于创建对象的接口, 让子类决定实例化哪个类. 工厂模式使1个类的实例化延迟到其子类.
上面那句话出现了4个对象.
分别是: 对象 接口 类 子类
它们的关系是这样的:
类 是指业务类,
对象 是 类 的实例化对象.
接口 指Java 的 interface 或者 抽象类. (工厂)
(工厂)子类 会创建1个 (业务)类 的 对象
至于延迟是什么意思? 还是在下面举个例子来讲把.
二. 手机的例子.
显示上手机有很多种. (包括Nokia手机, BlackBerry手机)
常用的功能有3种.
1. 打电话,
2. 发邮件.
3. 播放mp3.
现在有个人很有钱任性.
他有3台Nokia , 1台在打电话, 一台发邮件, 一台听歌..
用代码如何实现呢.
三. 简单工厂模式实现.
UML:

CellPhone接口:
public interface CellPhone {
public abstract void call();
public abstract void playMusic();
public abstract void sendEmail();
}
BlackBerry:
public class BlackBerry implements CellPhone {
@Override
public void call(){
System.out.println("calling by BlackBerry");
}
@Override
public void playMusic(){
System.out.println("playing Music by BlackBerry");
}
@Override
public void sendEmail(){
System.out.println("sending Email by BlackBerry");
}
}
Nokia:
public class Nokia implements CellPhone {
@Override
public void call(){
System.out.println("calling by nokia");
}
@Override
public void playMusic(){
System.out.println("playing Music by nokia");
}
@Override
public void sendEmail(){
System.out.println("sending Email by nokia");
}
}
工厂类CellPhoneFactory:
public class CellPhoneFactory {
public static CellPhone createCellPhone(String name){
CellPhone p = null;
switch(name){
case "Nokia" :
p = new Nokia();
break;
case "BlackBerry" :
p = new BlackBerry();
break;
}
return p;
}
}
客户端:
String name = "Nokia";
CellPhone p = CellPhoneFactory.createCellPhone(name);
CellPhone p2 = CellPhoneFactory.createCellPhone(name);
CellPhone p3 = CellPhoneFactory.createCellPhone(name);
p.call();
p2.sendEmail();
p3.playMusic();
四. 简单工厂的1个缺点.
简单工厂对客户端封装了真正的业务类, 这是以前说过的.
但是如果我要增加1个业务, 例如那个人想用一台Sony手机.
除了修改客户端代码外
那么我必须新增1个Sony类 -> 符合封闭-开放原则
五. 工厂方法的实现.
UML:

其中CellPhone, BlackBerry, Nokia3个类或接口跟上面是一样的没有变化.
工厂抽象类CellPhoneFactory:
现在这个类变成了抽象类了.public abstract class CellPhoneFactory {
public abstract CellPhone createCellPhone();
}
NokiaFactory:
Nokia工厂, 只会创建Nokia对象, 而且创建对象的方法已经不是静态方法, 需要实例化1个工厂来创建.
public class NokiaFactory extends CellPhoneFactory{
@Override
public CellPhone createCellPhone(){
return new Nokia();
}
}
BlackBerryFactory:
public class BlackBerryFactory extends CellPhoneFactory{
@Override
public CellPhone createCellPhone(){
return new BlackBerry();
}
}
客户端代码:
CellPhoneFactory factory = new NokiaFactory();
CellPhone p = factory.createCellPhone();
CellPhone p2 = factory.createCellPhone();
CellPhone p3 = factory.createCellPhone();
p.call();
p2.sendEmail();
p3.playMusic();
六. 工厂方法与简单工厂方法的区别.
好了, 通过对比, 我们知道区别如下:
1. 简单工厂的工厂类是1个非抽象类. 而工厂方法的工厂类是一个抽象类(或者接口), 它下面还有子类.
2. 简单工厂的业务类对象由工厂类的静态方法直接创建, 而工厂方法的业务类对象由工厂类的子类来创建.
这个就是工厂方法里, 那句" 工厂模式使1个类的实例化延迟到其子类" 的原因, 延迟是相当于简单工厂来讲的.
如果要新增1个sony手机.
工厂方法, 除了修改客户端代码之外,
还需要
新加个sony手机类.
新家1个sony手机工厂类.
看起来是完全符合开放-封闭原则的.
但是实际上, 简单工厂方法的判断在工厂类的switch字句内.
而工厂方法看起来不需要判断, 但实际上是把判断交给了客户端.
也就是说这一句
CellPhoneFactory factory = new NokiaFactory();
客户端需要自己判断使用哪个工厂.
而简单工厂只需要传入"Nokia"的名字就得到对应的业务对象.
有没有折中方法呢? 就是只需要手机名字的参数, 而且符合开放封闭原则的写法.
那就需要利用java里的反射机制.(所谓反射就是可以根据类名获取哪个类的对象或其他资源)
七. 反射简单工厂.
重写简单工厂的工厂类, 不使用switch 字句, 而是java的反射..
public class CellPhoneReflectFactory {
public static CellPhone createCellPhone(String name){
Class<?> c = null;
Class<?>[] argTypes = {}; //指明所要调用的构造方法的形参
Constructor<?> cst = null;
CellPhone p = null;
Object obj = null;
try {
c = (Class<?>) Class.forName("factory.simple." + name);
cst = c.getConstructor(argTypes);//获取指定参数的构造方法
obj = cst.newInstance(argTypes);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
p = (CellPhone)obj;
return p;
}
}
而客户端的写发不需要改变, 新增业务类也无需修改这个工厂类了.