一、定义
定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延伸到其子类。
简单的说,就是定义一个工厂,由工厂的生产方法来生产具体的产品类,用户只需要调用工厂的生产方法来获取具体的产品,而不需要关心生产的过程。
二、优点
1.拥有良好的封装性。调用者需要一个具体产品,只需要向工厂获取,而不用知道创建对象的艰辛过程,降低模块间的耦合。
2.易于扩展。增加产品时,只需要适当修改具体的工厂类或者扩展一个工厂,甚至不用修改。
3.屏蔽产品类,解除耦合。产品类的实现如何变化,调用者都不需要关心,只需要关心产品的接口即可。
三、女娲造人实例分析
大家都听过女娲捏土造人的神话故事,这软件开发中,这个过程设计到三个对象:女娲、八卦炉、不同肤色的人。女娲可以使用场景类 Client 表示,八卦炉类似于一个工厂 Factory,负责制造具体的产品 Product(即人类 Human)。相应的类图如下:
AbstractHumanFactory 的代码可以如下定义:
public abstract class AbstractHumanFactory { public abstract <T extends Human> T createHuman(Class<T> c); }
泛型限定了创建方法返回的对象类型必须是人类 Human。
HumanFactory 的代码可以如下定义:
public class HumanFactory extends AbstractHumanFactory { public <T extends Human> T createHuman(Class<T> c){ //定义一个生产的人种 Human human = null; try { //产生一个人种 human = (T)Class.forName(c.getName()).newInstance(); } catch (Exception e) { System.out.println("人种生成错误! "); } return (T)human; } }
使用反射可以避免新增产品时,还需要修改工厂的生产方法。
NvWa 类可以如下:
public class NvWa { public static void main(String[] args) { //声明阴阳八卦炉 AbstractHumanFactory YinYangLu = new HumanFactory();//女娲第一次造人, 火候不足, 于是白人产生了 System.out.println("--造出的第一批人是白色人种--"); Human whiteHuman = YinYangLu.createHuman(WhiteHuman.class); whiteHuman.getColor(); whiteHuman.talk(); //女娲第二次造人, 火候过足, 于是黑人产生了 System.out.println("--造出的第二批人是黑色人种--"); Human blackHuman = YinYangLu.createHuman(BlackHuman.class); blackHuman.getColor(); blackHuman.talk(); //第三次造人, 火候刚刚好, 于是黄色人种产生了 System.out.println("--造出的第三批人是黄色人种--"); Human yellowHuman = YinYangLu.createHuman(YellowHuman.class); yellowHuman.getColor(); yellowHuman.talk(); } }
四、简单工厂模式
当我们仅需要使用到一个工厂,我们没必要把它产生出来,同时使用静态方法就可以了。
例如上面女娲那个例子,我们可以去掉 AbstractHumanFactory 类,同时把 createHuman 方法设置为静态类型,简化了类的创建过程。类图如下:
类图变简单了,少了 AbstractHumanFactory 类,调用也比较简单,该模式是工厂方法模式的弱化,因为简单,所以称之为简单工厂模式,也叫静态工厂模式。
新的 HumanFactory 的代码可以如下定义:
public class HumanFactory { public static <T extends Human> T createHuman(Class<T> c){//定义一个生产出的人种 Human human = null; try { //产生一个人种 human = (Human)Class.forName(c.getName()).newInstance(); } catch (Exception e) { System.out.println("人种生成错误! "); } return (T)human; } }其优点是简单,缺点是工厂类的扩展比较困难,不符合开闭原则。