设计模式 工厂模式

1 场景问题

实现一个导出数据的应用框架,来让客户选择数据的导出方式,并真正执行数据导出。

有何问题

分析上面要实现的应用框架,不管用户选择什么样的导出格式,最后导出的都是一个文件,而且系统并不知道究竟要导出成为什么样的文件,因此应该有一个统一的接口,来描述系统最后生成的对象,并操作输出的文件。

ExportFileApi接口:
boolean export(String 数据); 导出方法 返回成功失败

/**
 * <p><b>类描述:导出的文件对象的接口</b> 
 * 不管用户选择什么样的导出格式,最后导出的都是一个文件,
 * 而且系统并不知道究竟要导出成为什么样的文件,因此应该有一个统一的接口,
 * 来描述系统最后生成的对象,并操作输出的文件。
 * </p>
 * @author mengqa 
*/
public interface ExportFileApi {

    public boolean export(String data);


}

对于实现导出数据的业务功能对象,它应该根据需要来创建相应的ExportFileApi的实现对象,因为特定的ExportFileApi的实现是与具体的业务相关的。但是对于实现导出数据的业务功能对象而言,它并不知道应该创建哪一个ExportFileApi的实现对象,也不知道如何创建。

也就是说:
对于实现导出数据的业务功能对象,它需要创建ExportFileApi的具体实例对象,但是它只知道ExportFileApi接口,而不知道其具体的实现.
那该怎么办呢?

解决方案

2.1 工厂方法模式来解决

用来解决上述问题的一个合理的解决方案就是工厂方法模式。那么什么是工厂方法模式呢?

定义一个用于创建对象的接口,让子类决定实例化哪一个类,Factory Method使一个类的实例化延迟到其子类。

2.2 应用工厂方法模式来解决的思路

仔细分析上面的问题,事实上在实现导出数据的业务功能对象里面,根本就不知道究竟要使用哪一种导出文件的格式,因此这个对象本就不应该和具体的导出文件的对象耦合在一起,它只需要面向导出的文件对象的接口就好了。

但是这样一来,又有新的问题产生了:接口是不能直接使用的,需要使用具体的接口实现对象的实例。

这不是自相矛盾吗?要求面向接口,不让和具体的实现耦合,但是又需要创建接口的具体实现对象的实例。怎么解决这个矛盾呢?

工厂方法模式的解决思路很有意思,那就是不解决,采取无为而治的方式:不是需要接口对象吗,那就定义一个方法来创建;可是事实上它自己是不知道如何创建这个接口对象的,没有关系,那就定义成抽象方法就好了,自己实现不了,那就让子类来实现,这样这个对象本身就可以只是面向接口编程,而无需关心到底如何创建接口对象了

2.2 模式结构和说明

工厂模式结构

Product:定义工厂方法所创建的对象的接口,也就是实际需要使用的对象的接口。

ConcreteProduct:具体的Product接口的实现对象。

Creator:创建器,声明工厂方法,工厂方法通常会返回一个Product类型的实例对象,而且多是抽象方法。也可以在Creator里面提供工厂方法的默认实现,让工厂方法返回一个缺省的Product类型的实例对象。

ConcreteCreator:具体的创建器对象,覆盖实现Creator定义的工厂方法,返回具体的Product实例。

具体代码

Prodcut的定义:

/**
 * <p><b>类描述:</b> 
 * 定义工厂方法所创建的对象的接口,也就是实际需要使用的对象的接口。
 * </p>
 * @author mengqa 
*/
public interface Product {

    /**
     * 一些属性和方法
     */
}

再看看具体的Product的实现对象,示例代码如下:

/**
 * <p><b>类描述:</b> 
 * Product具体的实现
 * </p>
 * @author mengqa 
*/
public class ConcreteProduct implements Product {

    /**
     * 实现Product的具体某些方法
     */

}

接下来看看创建器的定义,示例代码如下:

/**
 * <p><b>创造器</b> 
 * @author mengqa 
*/
public abstract class Creator {

    /**
     * <p><b>方法描述:</b>工厂方法</p>
     * 工厂方法通常会返回一个Product类型的实例对象,而且多是抽象方法
     * @since 
     * @return
     */
    public abstract Product factoryMethod();
    // 注: 也可以在Creator里面提供工厂方法的默认实现,让工厂方法返回一个缺省的Product类型的实例对象。

    /**
     * 示意方法,实现某些功能的方法
     */
    public void someOperate() {
        //通常在这些方法实现中,需要调用工厂方法来获取Product对象
        Product p = factoryMethod();
        // ....用p进行操作....
    }

}

再看看具体的创建器实现对象,示例代码如下:


/**
 * <p><b>创造器的具体实现</b> 
 * 具体的创建器对象,覆盖实现Creator定义的工厂方法,返回具体的Product实例。
 * </p>
 * @author mengqa 
*/
public class ConcreteCreator extends Creator {

    /**
     * <p><b>方法描述:</b>工厂方法</p>
     * 覆盖实现Creator定义的工厂方法,返回具体的Product实例。
     * @since 
     * @return Product
     */
    public Product factoryMethod() {
        return new ConcreteProduct();
    }

}

2.4 使用工厂方法模式来实现示例

1.ExportFileApi 就相当于Product

/**
 * <p><b>类描述:导出的文件对象的接口</b> 
 * 不管用户选择什么样的导出格式,最后导出的都是一个文件,
 * 而且系统并不知道究竟要导出成为什么样的文件,因此应该有一个统一的接口,
 * 来描述系统最后生成的对象,并操作输出的文件。
 * </p>
 * <p><b>创建时间:</b>2017年9月3日</p>
 * @author mengqa 
*/
public interface ExportFileApi {
    public boolean export(String data);
}

2.TxtExportImpl,ExcelExportImpl
就相当于ConcreteProduct

/**
 * <p><b>类描述:Txt导出实现</b> 
*/
public class TxtExportImpl implements ExportFileApi {

    @Override
    public boolean export(String data) {
        System.out.println("需要导出的数据为:" + data);
        System.out.println("稍等...正在导出txt文件");
        return true;
    }

}

3.用来实现导出数据的业务功能对象就相当于 Creator, 即ExportFunction

/**
 * <p><b>类描述:</b> 
 * @author mengqa 
*/
public abstract class ExportFunction {

    // 工厂方法, 用来创造ExportFileApi具体实现对象
    abstract ExportFileApi factoryMethod();

    // 导出方法
    void export(String data) {
        // 用就好了,不用管, 反正子类会去实现
        ExportFileApi exportFileApi = factoryMethod();
        boolean export = exportFileApi.export(data);
        // ... 后续处理代码 ...
    }
}

4.TxtExportCreator,ExcelExportCreator, 相当于ConcreteCreator

/**
 * <p><b>类描述:TxtExport对象工厂</b> 
*/
public class TxtExportCreator extends ExportFunction {

    @Override
    ExportFileApi factoryMethod() {
        return new TxtExportImpl();
    }

}

3.何时选用工厂方法模式

如果一个类需要创建某个接口的对象,但是又不知道具体的实现,这种情况可以选用工厂方法模式,把创建对象的工作延迟到子类去实现。

如果一个类本身就希望,由它的子类来创建所需的对象的时候,应该使用工厂方法模式。

参考文档:
http://www.jianshu.com/nb/4583287

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值