工厂方法(Factory Method)模式的意义是定义一个创建产品对象的工厂接口,将实际创建工作推迟到子类当中。核心工厂类不再负责产品的创建,这样核心类成为一个抽象工厂角色,仅负责具体工厂子类必须实现的接口,这样进一步抽象化的好处是使得工厂方法模式可以使系统在不修改具体工厂角色的情况下引进新的产品。
定义:
定义一个用于创建对象的接口,让子类决定实例化哪个类,Factory Method使一个类的实例化延迟到子类。
结构:
说明:
Product接口:工厂方法创建的对象的接口。
ConcreteProduct类,接口的具体实现。
Creator类,创建器,声明个工厂方法,通常返回一个Product类型的实例对象。
ConcreteCreator类,具体的创建器对象,覆盖实现Creator定义的工厂方法,返回具体的Product 实例。
具体代码:
/** * 类说明: 创建产品对象的接口 * Time: 2013-9-27 下午4:52:49 * @author 凯文 加内特 * Company: http://weibo.com/u/3165936675 */ public interface Product { }
/** * 类说明: 实现 * Time: 2013-9-27 下午4:53:55 * @author 凯文 加内特 * Company: http://weibo.com/u/3165936675 */ public class ConcreteProduct implements Product { }
/** * 类说明: 创建器 * Time: 2013-9-27 下午4:54:37 * @author 凯文 加内特 * Company: http://weibo.com/u/3165936675 */ public abstract class Creator { protected abstract Product factoryMethod(); public void someOperation() { Product p = factoryMethod(); } }
/** * 类说明: 具体的创建器对象 * Time: 2013-9-27 下午4:56:16 * @author 凯文 加内特 * Company: http://weibo.com/u/3165936675 */ public class ConcreteCreator extends Creator { protected Product factoryMethod() { return new ConcreteProduct(); } }
模式应用代码:
将数据导入到DB、txt文件中,代码如下:
/** * 类说明: 导出的文件对象的接口,相当结构中的Product * Time: 2013-10-8 下午5:34:33 * @author 凯文加内特 * Company: http://weibo.com/u/3165936675 */ public interface ExportFileApi { /** * 导出内容成为文件 * @param data 示意:需要保存的数据 * @return 是否导出成功 */ public boolean export(String data);
/** * 类说明: 导出成数据库备份文件形式的对象,相当结构中的ConcreteProduct * Time: 2013-10-8 下午5:34:19 * @author 凯文加内特 * Company: http://weibo.com/u/3165936675 */ public class ExportDB implements ExportFileApi { public boolean export(String data) { //简单示意一下,这里需要操作数据库和文件 System.out.println("导出数据" + data + "到数据库备份文件"); return true; } }
/** * 类说明: 导出成文本文件格式的对象,相当结构中的ConcreteProduct * Time: 2013-10-8 下午5:35:42 * @author 凯文加内特 * Company: http://weibo.com/u/3165936675 */ public class ExportTxtFile implements ExportFileApi { public boolean export(String data) { //简单示意一下,这里需要操作文件 System.out.println("导出数据" + data + "到文本文件"); return true; } }
/** * 类说明: 实现导出数据的业务功能对象,相当结构中的ConcreteCreator,此处没有用抽象类 * Time: 2013-10-8 下午5:34:52 * @author 凯文加内特 * Company: http://weibo.com/u/3165936675 */ 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; } }
/** * 类说明: 客户端类 * Time: 2013-10-8 下午5:34:02 * @author 凯文加内特 * Company: http://weibo.com/u/3165936675 */ public class Client { public static void main(String[] args) { //创建需要使用的Creator对象 ExportOperate exportOperate = new ExportOperate(); //调用输出数据的功能方法,传入选择到处类型的参数 exportOperate.export(1, "测试数据"); } }
如果扩展一个导入到xml文件中的功能,则添加一个ExportOperate2类,继承ExportOperate类,并重写factoryMethod方法,再添加一个ExportXml类并实现导出接口ExportFileApi即可,原先代码不动,甚是方便,满足了开闭原则,示例代码如下:
/** * 类说明: 扩展ExportOperate对象,加入可以导出XML文件 * Time: 2013-10-8 下午5:35:32 * @author 凯文加内特 * Company: http://weibo.com/u/3165936675 */ public class ExportOperate2 extends ExportOperate { /** * 覆盖父类的工厂方法,创建导出的文件对象的接口对象 * @param type 用户选择的导出类型 * @return 导出的文件对象的接口对象 */ protected ExportFileApi factoryMethod(int type) { ExportFileApi api = null; //可以全部覆盖,也可以选择自己感兴趣的覆盖, //这里只想添加自己新的实现,其他的不管 if (type == 3) { api = new ExportXml(); } else { //其他的还是让父类来实现 api = super.factoryMethod(type); } return api; } }
/** * 类说明: 导出成xml文件的对象 * Time: 2013-10-8 下午5:35:51 * @author 凯文加内特 * Company: http://weibo.com/u/3165936675 */ public class ExportXml implements ExportFileApi { public boolean export(String data) { //简单示意一下 System.out.println("导出数据" + data + "到XML文件"); return true; } }
/** * 类说明: 客户端类 * Time: 2013-10-8 下午5:34:02 * @author 凯文加内特 * Company: http://weibo.com/u/3165936675 */ public class Client { public static void main(String[] args) { //创建需要使用的Creator对象 ExportOperate exportOperate2 = new ExportOperate2(); //下面变换传入的参数来测试参数化工厂方法 exportOperate2.export(1, "Test1"); exportOperate2.export(2, "Test2"); exportOperate2.export(3, "Test3"); } }
使用场景:
如果一个类需要创建一个接口的对象,但是又不知道具体的实现,这种情况下可以选择工厂方法模式。把创建对象的工作延迟到子类去实现。
优点和缺点:
优点:
可以在不知道具体实现的情况下进行编程。
容易扩展, 当系统扩展需要添加新的产品对象时,仅仅需要添加一个具体对象以及一个具体工厂对象,原有工厂对象不需要进行任何修改,也不需要修改客户端,很好的符合了"开放-封闭"原则。而 简单工厂模式在添加新产品对象后不得不修改工厂方法,扩展性不好。
缺点:
具体产品对象与工厂方法的耦合性
留给自己的问题:
1.jdk、spring等开源源码中的示例