Java 工厂方法模式5(一)

2014-11-24 03:22:03 · 作者: · 浏览: 0

3.3 平行的类层次结构

(1)什么是平行的类层次结构呢?
简单点说,假如有两个类层次结构,其中一个类层次中的每个类在另一个类层次中都有一个对应的类的结构,就被称为平行的类层次结构。
举个例子来说,硬盘对象有很多种,如分成台式机硬盘和笔记本硬盘,在台式机硬盘的具体实现上面,又有希捷、西数等不同品牌的实现,同样在笔记本硬盘上,也有希捷、日立、IBM等不同品牌的实现;硬盘对象具有自己的行为,如硬盘能存储数据,也能从硬盘上获取数据,不同的硬盘对象对应的行为对象是不一样的,因为不同的硬盘对象,它的行为的实现方式是不一样的。如果把硬盘对象和硬盘对象的行为分开描述,那么就构成了如图10所示的结构:

\
图10 平行的类层次结构示意图

硬盘对象是一个类层次,硬盘的行为这边也是一个类层次,而且两个类层次中的类是对应的。台式机西捷硬盘对象就对应着硬盘行为里面的台式机西捷硬盘的行为;笔记本IBM硬盘就对应着笔记本IBM硬盘的行为,这就是一种典型的平行的类层次结构。
这种平行的类层次结构用来干什么呢?主要用来把一个类层次中的某些行为分离出来,让类层次中的类把原本属于自己的职责,委托给分离出来的类去实现,从而使得类层次本身变得更简单,更容易扩展和复用。
一般来讲,分离出去的这些类的行为,会对应着类层次结构来组织,从而形成一个新的类层次结构,相当于原来对象的行为的这么一个类层次结构,而这个层次结构和原来的类层次结构是存在对应关系的,因此被称为平行的类层次结构。

(2)工厂方法模式跟平行的类层次结构有何关系呢?
可以使用工厂方法模式来连接平行的类层次。
看上面的示例图10,在每个硬盘对象里面,都有一个工厂方法createHDOperate,通过这个工厂方法,客户端就可以获取一个跟硬盘对象相对应的行为对象。在硬盘对象的子类里面,会覆盖父类的工厂方法createHDOperate,以提供跟自身相对应的行为对象,从而自然的把两个平行的类层次连接起来使用。

3.4 参数化工厂方法

所谓参数化工厂方法指的就是:通过给工厂方法传递参数,让工厂方法根据参数的不同来创建不同的产品对象,这种情况就被称为参数化工厂方法。当然工厂方法创建的不同的产品必须是同一个Product类型的。
来改造前面的示例,现在有一个工厂方法来创建ExportFileApi这个产品的对象,但是ExportFileApi接口的具体实现很多,为了方便创建的选择,直接从客户端传入一个参数,这样在需要创建ExportFileApi对象的时候,就把这个参数传递给工厂方法,让工厂方法来实例化具体的ExportFileApi实现对象。
还是看看代码示例会比较清楚。
(1)先来看Product的接口,就是ExportFileApi接口,跟前面的示例没有任何变化,为了方便大家查看,这里重复一下,示例代码如下:

/**

* 导出的文件对象的接口

*/

public interface ExportFileApi {

/**

* 导出内容成为文件

* @param data 示意:需要保存的数据

* @return 是否导出成功

*/

public boolean export(String data);

}

(2)同样提供保存成文本文件和保存成数据库备份文件的实现,跟前面的示例没有任何变化,示例代码如下:

public class ExportTxtFile implements ExportFileApi{

public boolean export(String data) {

//简单示意一下,这里需要操作文件

System.out.println("导出数据"+data+"到文本文件");

return true;

}

}

public class ExportDB implements ExportFileApi{

public boolean export(String data) {

//简单示意一下,这里需要操作数据库和文件

System.out.println("导出数据"+data+"到数据库备份文件");

return true;

}

}

(3)接下来该看看ExportOperate类了,这个类的变化大致如下:

  • ExportOperate类中的创建产品的工厂方法,通常需要提供默认的实现,不抽象了,也就是变成正常方法
  • ExportOperate类也不再定义成抽象类了,因为有了默认的实现,客户端可能需要直接使用这个对象
  • 设置一个导出类型的参数,通过export方法从客户端传入

    看看代码吧,示例代码如下:

    /**

    * 实现导出数据的业务功能对象

    */


    public class ExportOperate {

    /**

    * 导出文件

    * @param type 用户选择的导出类型


    * @param data 需要保存的数据

    * @return 是否成功导出文件

    */

    public boolean export(int type,String data){

    //使用工厂方法

    ExportFileApi api = factoryMethod(type);

    return api.export(data);

    }

    /**

    * 工厂方法,创建导出的文件对象的接口对象

    * @param type 用户选择的导出类型

    * @return 导出的文件对象的接口对象

    */

    protected ExportFileApi factoryMethod(int type){


    ExportFileApi api = null;

    //根据类型来选择究竟要创建哪一种导出文件对象

    if(type==1){

    api = new ExportTxtFile();

    }else if(type==2){

    api = new ExportDB();

    }

    return api;

    }

    }

    (4)此时的客户端,非常简单,直接使用ExportOperate类,示例代码如下:

    public class Client {

    public static void main(String[] args) {

    //创建需要使用的Creator对象

    ExportOperate operate = new ExportOperate();

    //调用输出数据的功能方法,传入选择到处类型的参数

    operate.export(1,"测试数据");

    }

    }

    测试看看,然后修改一下客户端的参数,体会一下通过参数来选择具体的导出实现的过程。这是一种很常见的参数化工厂方法的实现方式,但是也还是有把参数化工厂方法实现成为抽象的,这点要注意,并不是说参数化工厂方法就不能实现成为抽象类了。只是一般情况下,参数化工厂方法,在父类都会提供默认的实现。

    (5)扩展新的实现
    使用参数化工厂方法,扩展起来会非常容易,已有的代码都不会改变,只要新加入一个子类来提供新的工厂方法实现,然后在客户端使用这个新的子类即可。
    这种实现方式还有一个有意思的功能,就是子类可以选择性覆盖,不想覆盖的功能还可以返回去让父类来实现,很有意思。
    先扩展一个导出成xml文件的实现,试试看,示例代码如下:

    /**

    * 导出成xml文件的对象

    */

    public class ExportXml implements ExportFileApi{

    public boolean export(String data) {

    //简单示意一下

    System.out.println("导出数据"+data+"到XML文件");

    return true;

    }