工厂方法模式

来源:互联网 发布:域名的所有权 编辑:程序博客网 时间:2024/05/29 21:33

工厂方法模式的定义

定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟至其子类。

工厂方法模式的通用类图如下:

工厂方法模式

抽象产品类Product负责定义产品的共性,实现对事物最抽象的定义:Creator为抽象创建类,也就是抽象工厂,具体如何创建产品类是由具体的实现工厂ConcreteCreator完成的。让我们来看一个比较实用的通用源码:

抽象产品类:

/** * 抽象产品类 */public abstract class Product {    //产品类的公共方法    public void method1() {        //业务逻辑处理    }    //抽象方法    public abstract void method2();}

具体产品类:

/** * 具体产品类1 */public class ConcreteProduct1 extends Product {    @Override    public void method2() {        //业务逻辑处理    }}/** * 具体产品类2 */public class ConcreteProduct2 extends Product {    @Override    public void method2() {        //业务逻辑处理    }}

抽象工厂类:

/** * 抽象工厂类 */public abstract class Creator {    /*    * 创建一个产品对象,其输入参数类型可以自行设置    * 通常为String、Enum、Class等,当然也可以为空    * */    public abstract <T extends Product> T createProduct(Class<T> c);}

具体工厂类:

/** * 具体工厂类 */public class ConcreteCreator extends Creator {    @Override    public <T extends Product> T createProduct(Class<T> c) {        Product product = null;        try {            product = (Product) Class.forName(c.getName()).newInstance();        } catch (Exception e) {            e.printStackTrace();        }        return (T) product;    }}

场景类:

/** * 场景类 */public class Client {    public static void main(String[] args) {        Creator creator = new ConcreteCreator();        Product product = creator.createProduct(ConcreteProduct1.class);        //继续业务处理    }}

工厂方法模式的应用

工厂方法模式的优点

  • 良好的封装性,代码结构清
  • 工厂方法模式的扩展性非常优秀
  • 屏蔽产品类
  • 工厂方法模式是典型的解耦框架

工厂方法模式的使用场景

  • 工厂方法模式是new一个对象的替代品,所以在所有需要生成对象的地方都可以使用,但是需要慎重地考虑是否要增加一个工厂类进行管理,增加代码复杂度。
  • 需要灵活的、可扩展的框架时,可以考虑采用工厂方法模式。
  • 工厂方法模式可以用于异构项目中,例如通过WebService与一个非Java的项目交互。
  • 可以使用在测试驱动开发的框架下。

工厂方法模式实例

通过工厂方法模式来实现女娲造人,生产各种人种。代码如下:

人类总称:

/** * 人类总称 */public interface Human {    //每个人中的皮肤都有相应的颜色    public void getColor();    //人类会说话    public void talk();}

人种:

/** * 黑色人种 */public class BlackHuman implements Human {    @Override    public void getColor() {        System.out.println("黑色人种的皮肤颜色是黑色的!");    }    @Override    public void talk() {        System.out.println("黑人会说话,一般人听不懂。");    }}/** * 白色人种 */public class WhiteHuman implements Human {    @Override    public void getColor() {        System.out.println("白色人种");    }    @Override    public void talk() {        System.out.println("白色人种说话");    }}/** * 黄色人种 */public class YellowHuman implements Human {    @Override    public void getColor() {        System.out.println("黄色人种的皮肤颜色是黄色的");    }    @Override    public void talk() {        System.out.println("黄色人种说话");    }}

抽象人类创建工厂:

/** * 抽象人类创建工厂 */public abstract class AbstractHumanFactory {    public abstract <T extends Human> T createHuman(Class<T> c);}

人类创建工厂:

/** * 人类创建工厂 */public class HumanFactory extends AbstractHumanFactory {    @Override    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;    }}

女娲类:

/** * 女娲 */public class NvWa {    public static void main(String[] args) {        //声明阴阳八卦炉        AbstractHumanFactory yinyanglu = new HumanFactory();        //女娲造白人        System.out.println("白人");        Human white = yinyanglu.createHuman(WhiteHuman.class);        white.getColor();        white.talk();        System.out.println("黑人");        Human black = yinyanglu.createHuman(BlackHuman.class);        black.getColor();        black.talk();        System.out.println("黄人");        Human yellow = yinyanglu.createHuman(YellowHuman.class);        yellow.getColor();        yellow.talk();    }}

工厂方法模式的扩展

缩小为简单工厂模式

一个模块仅需要一个工厂类,没有必要把它生产出来,使用静态的方法就可以了。

代码如下:

简单工厂模式中的工厂类:

/** * 简单工厂模式中断工厂类 */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) {            e.printStackTrace();        }        return (T) human;    }}

HumanFactory类仅有两个地方发生变化:去掉继承抽象类,并在createHuman前增加static关键字。

简单工厂模式中的场景类:

public class NvWa {    public static void main(String[] args) {        Human white = HumanFactory.createHuman(WhiteHuman.class);        white.getColor();        white.talk();    }}

运行结果没有变化,但是类图和调用者也简化了,该模式是工厂方法模式的弱化,以为简单,所以称为简单工厂模式(Simple Factory Pattern),也叫做静态工厂模式

升级为多个工厂类

当我们在做一个比较复杂的项目的时候,经常会遇到初始化一个对象很耗费精力的情况,所有的产品类都放到一个工厂方法中进行初始化会使代码结构不清晰。为此,我们就为每一个产品定义一个创造者,然后由调用者自己去选择与哪个工厂方法关联。

多工厂模式的抽象工厂类:

/** * 多工厂模式的抽象工厂类 */public abstract class AbstractHumanFactory {    public abstract Human createHuman();}

人种的创建工厂实现:

/** * 黑色人种的创建工厂实现 */public class BlackHumanFactory extends AbstractHumanFactory {    @Override    public Human createHuman() {        return new BlackHuman();    }}//...

场景类NvWa

/** * 场景类NvWa */public class NvWa {    public static void main(String[] args) {        Human black = (new BlackHumanFactory()).createHuman();        black.getColor();        black.talk();        //...    }}

每一个产品类都对应了一个创建类,好处就是创建类的职责清晰,而且结构简单,但是给可扩展性和可维护性带来了一定的影响。因为如果要扩展一个产品类,就需要建立一个相应的工厂类,这样就增加了扩展的难度。

当然,在复杂的应用中一般采用多工厂模式,然后再增加一个协调类,避免调用者与各个子工厂交流,协调类的作用是封装子工厂类,对高层模块提供统一的访问接口。

替代单例模式

通过工厂方法模式实现只在内存中生产一个对象。

代码定义如下:

单例类:

/** * 单例类 */public class Singleton {    //不允许通过new产生一个对象    private Singleton() {    }    public void doSomething() {    }}

负责生成单例的工厂类:

/** * 负责生成单例的工厂类 */public class SingletonFactory {    private static Singleton singleton;    static {        try {            Class cl = Class.forName(Singleton.class.getName());            //获取无参构造            Constructor constructor = cl.getDeclaredConstructor();            //设置无参构造是可访问的            constructor.setAccessible(true);            //产生一个实例对象            singleton = (Singleton) constructor.newInstance();        } catch (Exception e) {            e.printStackTrace();        }    }    public static Singleton getSingleton() {        return singleton;    }}

以上通过工厂方法模式创建了一个单例对象,该框架可以继续扩展,在一个项目中可以产生一个单例构造器,所有需要产生单例的类都遵循一定的规则(构造方法是private),然后通过扩展该框架,只需要输入一个类型就可以获得唯一的一个实例。

延迟初始化

延迟初始化(Lazy initialization)意为一个对象被消费完毕后,并不立刻释放,工厂类保持其初始状态,等待再次被使用。延迟初始化是工厂方法模式的一个扩展应用

其代码如下:

延迟加载的工厂类:

/** * 延迟加载的工厂类 */public class ProductFactory {    private static final Map<String, Human> map = new HashMap<>();    public static synchronized Human createHuman(String type) throws Exception {        Human human = null;        //如果Map中已经有这个对象        if (map.containsKey(type)) {            human = map.get(type);        } else {            if (type.equals("black")) {                human = new BlackHuman();            } else {                human = new YellowHuman();            }            map.put(type, human);        }        return human;    }}

延迟加载框架是可以扩展的,录入限制某个产品的最大实例化的数量,可以通过判定Map中已有的对象数量来实现,这样的处理是非常有意义的。延迟初始化还可以用在对象初始化比较复杂的情况下,来降低创建对象带来的消耗。


参考文献:《设计模式之禅》

原创粉丝点击