Java实现工厂方法模式

一、工厂方法模式的定义

工厂方法模式使用的频率非常高,在我们日常的开发中总能见到它的身影。其定义为:Define an interface for creating an object,but let subclasses decide which class toinstantiate.Factory Method lets a class defer instantiation to subclasses.(定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。)

1、工厂方法模式的通用类图

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

 

2、工厂方法模式通用模板。

抽象产品类:

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

具体的产品类可以有多个,都继承于抽象产品类,其源代码如下

/**
 * 具体的产品类可以有多个,都继承于抽象产品类
 */
public class ConcreteProduct1 extends Product {
    @Override
    public void method2() {

    }
}

package designPatterns.factoryMethodPattern.example2;
/**
 * 具体的产品类可以有多个,都继承于抽象产品类
 */
public class ConcreteProduct2 extends Product{
    @Override
    public void method2() {
        
    }
}

抽象工厂类负责定义产品对象的产生,源代码如下:

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

具体如何产生一个产品的对象,是由具体的工厂类实现的,如代码

package designPatterns.factoryMethodPattern.example2;

/**
 * 具体如何产生一个产品的对象,是由具体的工厂类实现的,代码如下。
 */
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 ex){
            System.out.println("生产失败......");
        }
        return (T)product;
    }
}

场景类的调用方法如代码

/**
 * 调用场景
 */
public class Client {
    public static void main(String[] args) {
        Creator creator = new ConcreteCreator();
        Product product = creator.createProduct(ConcreteProduct1.class);

        /**
         * 其它业务逻辑
         */
    }
}

该通用代码是一个比较实用、易扩展的框架,读者可以根据实际项目需要进行扩展。

二、工厂方法模式的应用

1、工厂方法模式的优点

 

首先,良好的封装性,代码结构清晰。一个对象创建是有条件约束的,如一个调用者需要一个具体的产品对象,只要知道这个产品的类名(或约束字符串)就可以了,不用知道创建对象的艰辛过程,降低模块间的耦合。

其次,工厂方法模式的扩展性非常优秀。在增加产品类的情况下,只要适当地修改具体的工厂类或扩展一个工厂类,就可以完成“拥抱变化”。例如在我们的例子中,需要增加一个棕色人种,则只需要增加一个BrownHuman类,工厂类不用任何修改就可完成系统扩展。

再次,屏蔽产品类。这一特点非常重要,产品类的实现如何变化,调用者都不需要关心,它只需要关心产品的接口,只要接口保持不变,系统中的上层模块就不要发生变化。因为产品类的实例化工作是由工厂类负责的,一个产品对象具体由哪一个产品生成是由工厂类决定的。在数据库开发中,大家应该能够深刻体会到工厂方法模式的好处:如果使用JDBC连接数据库,数据库从MySQL切换到Oracle,需要改动的地方就是切换一下驱动名称(前提条件是SQL语句是标准语句),其他的都不需要修改,这是工厂方法模式灵活性的一个直接|案例。

最后,工厂方法模式是典型的解耦框架。高层模块值需要知道产品的抽象类,其他的实现类都不用关心,符合迪米特法则,我不需要的就不要去交流;也符合依赖倒置原则,只依赖产品类的抽象;当然也符合里氏替换原则,使用产品子类替换产品父类,没问题!

 

2、工厂方法模式的使用场景

首先,工厂方法模式是new一个对象的替代品,所以在所有需要生成对象的地方都可以使用,但是需要慎重地考虑是否要增加一个工厂类进行管理,增加代码的复杂度。

其次,需要灵活的、可扩展的框架时,可以考虑采用工厂方法模式。万物皆对象,那万物也就皆产品类,例如需要设计一个连接邮件服务器的框架,有三种网络协议可供选择: POP3IMAPHITP,我们就可以把这三种连接方法作为产品类,定义一个接口如IConnectMail,然后定义对邮件的操作方法,用不同的方法实现三个具体的产品类(也就是连接方式)再定义一个工厂方法,按照不同的传入条件,选择不同的连接方式。如此设计,可以做到完美的扩展,如某些邮件服务器提供了WebService接口,很好,我们只要增加一个产品类就可以了。

再次,工厂方法模式可以用在异构项目中,例如通过WebService与一个非Java的项目交互,虽然WebService号称是可以做到异构系统的同构化,但是在实际的开发中,还是会碰到很多问题,如类型问题、WSDL文件的支持问题,等等。从WSDL中产生的对象都认为是一个产品,然后由一个具体的工厂类进行管理,减少与外围系统的耦合。

最后,可以使用在测试驱动开发的框架下。例如,测试一个类A,就需要把与类A有关联关系的类B也同时产生出来,我们可以使用工厂方法模式把类B虚拟出来,避免类A与类B的耦合。目前由于JMock和EasyMock的诞生,该使用场景已经弱化了,读者可以在遇到此种情况时直接考虑使用JMock或EasyMock。

三、工厂方法模式的扩展

  1. 使用工厂方法模式实现单例模式

(1)、工厂方法模式替代单例模式的类图;

非常简单的类图,Singleton定义了一个private的无参构造函数,目的是不允许通过new的方式创建一个对象,代码如下。

package designPatterns.factoryMethodPattern.example2;

/**
 * 工厂方法模式替代单例模式
 */
public class Singleton {

    // 私有化构造函数
    private Singleton (){

    }
    // 其它方法
    public void doSomething(){

    }
}

SingletonFactor工厂方法模式实现单例模式的代码如下。这里主要采用了反射的方式创建对象。

package designPatterns.factoryMethodPattern.example2;
import java.lang.reflect.Constructor;
/**
 * 工厂方法模式采用反射实现单例模式
 */
public class SingletonFactory {
    private static Singleton singleton;
    static{
        try{
            // 反射获取类对象
            Class c = Class.forName(Singleton.class.getName());
            // 获得无参数构造函数
            Constructor constructor = c.getDeclaredConstructor();
            // 设置无参构造函数的访问权限
            constructor.setAccessible(true);
            // 产生一个实例对象
            singleton = (Singleton)constructor.newInstance();
        }catch(Exception ex){
            // 异常处理
        }
    }
}

通过获得类构造器,然后设置访问权限,生成一个对象,然后提供外部访问,保证内存中的对象唯一

工厂方法模式在项目中使用得非常频繁,以至于很多代码中都包含工厂方法模式。该模式几乎尽人皆知,但不是每个人都能用得好。熟能生巧,熟练掌握该模式,多思考工厂方法如何应用,而且工厂方法模式还可以与其他模式混合使用(例如模板方法模式、单例模式、原型模式等),变化出无穷的优秀设计,这也正是软件设计和开发的乐趣所在。

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值