设计模式之工厂方法模式
工厂方法模式
1.工厂方法模式之定义
定义一个用于创建对象的接口,让子类去决定实例化哪一个类,工厂方法,使得一个类的实例化延迟到其子类。主要功能让父类在不知道具体实现的情况下,完成自身的功能调用,而具体的实现延伸到子类实现。工厂方法的实现中,通常父类会是一个抽象类,里面包含所需对象的抽象方法,这些抽象方法就是工厂方法。
2.工厂方法模式之场景
考虑这样一个应用,实现一个导出数据的功能,让客户来选择导出方式然后导出数据。比如导出的格式有文本格式、数据库备份格式、Excel格式、xml格式而且导出的格式不同。如果使用简单工厂模式,则工厂类必定过于臃肿。因为简单工厂模式只有一个工厂类,它需要处理所有的创建的逻辑。假如以上需求暂时只支持3种导出的格式以及2种导出的结构,那工厂类则需要6个if else来创建6种不同的类型。如果日后需求不断增加,则后果不堪设想。这时候就需要工厂方法模式来处理以上需求。
在工厂方法模式中,核心的工厂类不再负责所有的对象的创建,而是将具体创建的工作交给子类去做。这个核心类则摇身一变,成为了一个抽象工厂角色,仅负责给出具体工厂子类必须实现的接口,而不接触哪一个类应当被实例化这种细节。
这种进一步抽象化的结果,使这种工厂方法模式可以用来允许系统在不修改具体工厂角色的情况下引进新的产品,这一特点无疑使得工厂方法模式具有超过简单工厂模式的优越性。下面就针对以上需求设计UML图:
3.根据上图可知工厂方法涉及到的角色
抽象工厂(ExportFactory)角色:担任这个角色的是工厂方法模式的核心,任何在模式中创建对象的工厂类必须实现这个接口。在实际的系统中,这个角色也常常使用抽象类实现。
具体工厂(ExportExcelFactory、ExportPdfFactory)角色:担任这个角色的是实现了抽象工厂接口的具体JAVA类。具体工厂角色含有与业务密切相关的逻辑,并且受到使用者的调用以
创建导出类(如:ExportStandardPdfFile)。
抽象导出(ExportFile)角色:工厂方法模式所创建的对象的超类,也就是所有导出类的共同父类或共同拥有的接口。在实际的系统中,这个角色也常常使用抽象类实现。
具体导出(ExportStandardTxtFile等)角色:这个角色实现了抽象导出(ExportFile)角色所声明的接口,工厂方法模式所创建的每一个对象都是某个具体导出角色的实例。
首先是抽象工厂角色源代码。它声明了一个工厂方法,要求所有的具体工厂角色都实现这个工厂方法。参数type表示导出的格式是哪一种结构,如:导出Excel格式有两种结构,一种是标准结构,一种是财务需要的结构。
4.源代码:
抽象工厂:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
public interface ExportFactory { ExportFile exportFactory(String type); }
具体工厂:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
public class ExportExcelFactory implements ExportFactory { @Override public ExportFile exportFactory(String type) { // TODO Auto-generated method stub if("s".equals(type)){ return new ExportStandardExcelFile(); }else if("f".equals(type)){ return new ExportFinancialExcelFile(); }else{ System.out.println("非法类型"); return null; } } } public class ExportPdfFactory implements ExportFactory { @Override public ExportFile exportFactory(String type) { if("s".equals(type)){ return new ExportStandardPdfFile(); }else if("f".equals(type)){ return new ExportFinancialPdfFile(); }else{ System.out.println("非法类型"); return null; } } }
抽象导出:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
public interface ExportFile { boolean export(String data); }
具体导出:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
public class ExportFinancialExcelFile implements ExportFile { @Override public boolean export(String data) { // TODO Auto-generated method stub //业务逻辑 System.out.println("导出财格式Excel成功"); return true; } } public class ExportFinancialPdfFile implements ExportFile { @Override public boolean export(String data) { // TODO Auto-generated method stub //业务逻辑 System.out.println("导出财务pdf成功"); return true; } } public class ExportStandardExcelFile implements ExportFile { @Override public boolean export(String data) { // TODO Auto-generated method stub //业务逻辑 System.out.println("导出标准Excel成功"); return true; } } public class ExportStandardPdfFile implements ExportFile { @Override public boolean export(String data) { // TODO Auto-generated method stub //业务逻辑 System.out.println("导出标准pdf成功"); return true; } }
测试:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
public class Test { public static void main(String[] args) { String data = "测试"; ExportFactory f = new ExportPdfFactory(); ExportFile e = f.exportFactory("s"); e.export(data); } }
5.总结:
工厂方法的参数和返回值,工厂方法的实现可能需要参数,以便决定选用哪一类的具体实现,一般工厂方法返回的的是被创建对象的接口对象,当然也可以是抽象类或者一个具体类的实现。
工厂方法模式和IOC/DI
依赖注入:应用程序依赖容器创建并注入它所需要的外部资源。
控制反转:容器控制应用程序,由容器反向向应用程序注入应用程序所需要的外部资源。
其实IOC/DI对编程带来最大的改变不是代码,而是思想上发生了主从换位的变化。和工厂模式方法的思想是相似的。
工厂模式方法的本质是:延迟到子类来选择实现。
工厂方法很好体现了依赖倒置原则,要依赖抽象而不是依赖具体的类,简单点说不能要高层组件依赖底层组件,而且不管高层还是底层,都应该依赖抽象。