Java设计模式-工厂方法模式(Virtual Constructor/Polymorphic Factory)
工厂方法模式(Virtual Constructor/Polymorphic Factory)
工厂方法模式是类的创建模式,又叫做虚拟构造子模式(Virtual Constructor)或者多态性工厂模式(Polymorphic Factory)。
工厂方法模式的用意是定义一个创建产品对象的工厂接口,将实际创建工作推迟到子类中。
那么工厂方法模式是在什么场景下使用呢?下面就举例说明:
相信很多人都做过导入导出功能,就拿导出功能来说。有这么一个需求:XX系统需要支持对数据库中的员工薪资进行导出,并且支持多种格式如:HTML,CSV,PDF等,每种格式导出的结构有所不同,比如财务跟其他人对导出薪资的HTML格式要求可能会不一样,因为财务可能需要特定格式方便核算或其他用途。
如果使用简单工厂模式,则工厂类必定过于臃肿。因为简单工厂模式只有一个工厂类,它需要处理所有的创建的逻辑。假如以上需求暂时只支持3中导出格式以及2中导出的结构,那工厂类则需要6个if else来创建6中不同的类型。如果日后需求不断增加,则后果不堪设想。
这时候就需要工厂方法模式来处理以上需求。在工厂方法模式中,核心的工厂类不再负责所有的对象的创建,而是将具体创建的工作交给子类去做。这个核心类摇身一变,成了一个抽象工厂角色,仅负责给出具体工厂子类必须实现的接口,而不接触哪一类应该被实例化这种细节。
这种进一步抽象化的结果,使这种工厂方法模式可以用来允许系统在不修改具体工厂角色的情况下引进新的产品,这一特点无疑使得工厂方法模式具有超过简单工厂模式的优越性。
从上图可以看出,这个使用的工厂方法模式的系统设计到以下角色:
抽象工厂(ExportFactory)角色:担任这个角色的是工厂方法模式的核心,任何在模式中创建对象的工厂类必须实现这个接口。在实际的系统中,这个角色也常常使用抽象类实现。
具体工厂(ExportHtmlFactory,ExportPdfFactory)角色:担任这个角色的是实现了抽象工厂接口的具体JAVA类。具体工厂角色含有与业务密切相关的逻辑,并且受到使用者的调用以创建导出类(如ExportStandardHtmlFile)。
抽象导出(ExportFile)角色:工厂方法模式所创建的对象的超类,也就是所有导出类的共同父类或共同拥有的接口。在实际的系统中,这个角色也常常使用抽象类实现。
具体导出(ExportStandardHtmlFile等)角色:这个角色实现了抽象导出(ExportFile)角色所声明的接口,工厂方法模式所创建的每一个对象都是某个具体导出角色的实例。
源代码
首先试抽象工厂角色源代码。它生命一个工厂方法,要求所有具体工厂角色都实现这个工厂方法。参数type表示导出的格式是哪一种结构,如导出HTML格式有两种结构,一种是标准结构,一种是财务需要的结构。
- package com.tutorialspoint;
- public interface ExportFactory {
- public ExportFile factory(String type);
- }
具体工厂角色类源代码:
ExportHtmlFactory:
- package com.tutorialspoint;
- public class ExportHtmlFactory implements ExportFactory {
- @Override
- public ExportFile factory(String type) {
- // TODO Auto-generated method stub
- if (type.equals("standard")) {
- return new ExportStandardHtmlFile();
- } else if ( type.equals("financial")) {
- return new ExportFinancialHtmlFile();
- } else {
- throw new RuntimeException();
- }
- }
- }
ExportPdfFactory:
- package com.tutorialspoint;
- public class ExportPdfFactory implements ExportFactory {
- @Override
- public ExportFile factory(String type) {
- // TODO Auto-generated method stub
- if ( type.equals("standard") ) {
- return new ExportStandardPdfFile();
- } else if ( type.equals("financial") ) {
- return new ExportFinancialPdfFile();
- } else {
- throw new RuntimeException();
- }
- }
- }
抽象导出角色类源代码:
- package com.tutorialspoint;
- public interface ExportFile {
- public boolean export(String data);
- }
具体导出角色类源代码,通常这个类会有复杂的业务逻辑。
ExportStandardHtmlFile:
- package com.tutorialspoint;
- public class ExportStandardHtmlFile implements ExportFile {
- @Override
- public boolean export(String data) {
- // TODO Auto-generated method stub
- System.out.println("导出标准HTML文件");
- return true;
- }
- }
ExportFinancialHtmlFile:
- package com.tutorialspoint;
- public class ExportFinancialHtmlFile implements ExportFile {
- @Override
- public boolean export(String data) {
- // TODO Auto-generated method stub
- System.out.println("导出财务版HTML文件");
- return true;
- }
- }
ExportStandardPdfFile:
- package com.tutorialspoint;
- public class ExportStandardPdfFile implements ExportFile {
- @Override
- public boolean export(String data) {
- // TODO Auto-generated method stub
- System.out.println("导出标准版PDF文件");
- return true;
- }
- }
ExportFinancialPdfFile:
- package com.tutorialspoint;
- public class ExportFinancialPdfFile implements ExportFile {
- @Override
- public boolean export(String data) {
- // TODO Auto-generated method stub
- System.out.println("导出财务版PDF文件");
- return false;
- }
- }
测试类:
- String data = "";
- String type = "standard";
- ExportFactory exportFactory = new ExportHtmlFactory();
- ExportFile exportFile = exportFactory.factory(type);
- exportFile.export(data);
- ExportFactory exportFactory1 = new ExportHtmlFactory();
- ExportFile exportFile1 = exportFactory1.factory("financial");
- exportFile1.export(data);
- ExportFactory exportFactory2 = new ExportPdfFactory();
- ExportFile exportFile2 = exportFactory2.factory("standard");
- exportFile2.export(data);
- ExportFactory exportFactory3 = new ExportPdfFactory();
- ExportFile exportFile3 = exportFactory3.factory("financial");
- exportFile3.export(data);
结果:
工厂方法模式的活动序列图:
客户端创建ExportHtmlFactory对象,这时客户端所持有变量的静态类型为ExportFactory,而实际类型为ExportHtmlFactory。然后客户端调用ExportHtmlFactory对象的工厂方法factory(),接着后者调用ExportStadardHtmlFile的构造子创建出导出对象。
工厂方法模式和简单工厂模式
工厂方法模式和简单工厂模式在结构上的不同很明显。工厂方法模式的核心是一个抽象工厂类,而简单工厂模式把核心放在一个具体类上。
工厂方法模式退化后可以变得很像简单工厂模式。设想如果非常确定一个系统只需要一个具体工厂类,那么不妨把抽象工厂类合并到具体工厂类中去。由于只有一个具体工厂类,所以不妨将工厂方法改为静态方法,这时候就得到了简单工厂模式。
如果系统需要加入一个新的导出类型,那么所需要的就是向系统加入一个到处类以及对应的工厂类,没必要修改客户端。也没必要修改抽象工厂角色或者其他已有的具体工厂角色。对于新增加的导出类型而言,这个系统完全支持“开-闭原则”。
总结
一个应用系统由多人开发,导出的功能是你实现的,但是使用者(调用这个方法的人)可能确实其他人。这时候你应该设计的足够灵活并尽量降低两者之间的耦合度。当你修改后增加一个新的功能时,使用者不需要修改任何地方。加入你设计不够灵活,那么将无法面对客户多变的需求。可能一个极小的需求变更,都会使你的代码结构发生改变,并导致其他使用你所提供的接口的人都要修改它们的代码。牵一处而动全身,使得日后这个系统难以维护。
Java设计模式-工厂方法模式(Virtual Constructor/Polymorphic Factory)的更多相关文章
- Objective-C设计模式——工厂方法模式virtual constructor(对象创建)
工厂方法模式 工厂方法模式可以控制对象的创建过程,屏蔽对象创建的细节,可以直接创建出我们所需要的已经配置好的对象. 工厂方法模式定义了创建方法的接口,让子类决定实例化哪一个类,工厂方法模式使得一个类的 ...
- JAVA设计模式--工厂方法模式
工厂方法设计模式 抽象工厂角色: 这是工厂方法模式的核心,它与应用程序无关.是具体工厂角色必须实现的接口或者必须继承的父类.在java中它由抽象类或者接口来实现.具体工厂角色:它含有和具体业务逻辑有关 ...
- 我的Java设计模式-工厂方法模式
女朋友dodo闹脾气,气势汹汹的说"我要吃雪糕".笔者心里啊乐滋滋的,一支雪糕就能哄回来,不亦乐乎?! 但是,雪糕买回来了,她竟然说"不想吃雪糕了,突然想吃披萨" ...
- Java设计模式—工厂方法模式&抽象工厂模式
工厂方法模式与抽象工厂模式都是设计模式中重要而且常见的模式. 工厂方法模式:定义一个用于创建对象的接口,让子类决定实例化哪一个类.工厂方法使一个类的实例化延迟到其子类. 通用类图如下: 在 ...
- Java设计模式-工厂方法模式(Factory Method)
工厂方法模式(Factory Method) 工厂模式适合:凡是出现了大量的产品需要创建,并且具有共同的接口时,可以通过工厂方法模式进行创建.在以下的三种模式中,第一种如果传入的字符串有误,不能正确创 ...
- Java设计模式---工厂方法模式(Factory-Method)
一.普通工厂模式 建立一个工厂类,对实现了同一接口的一些类进行实例的创建 实例代码: 发送短信和邮件的例子,首先创建接口: public interface Sender { public void ...
- 4. 星际争霸之php设计模式--工厂方法模式
题记==============================================================================本php设计模式专辑来源于博客(jymo ...
- C++设计模式——工厂方法模式
本文版权归果冻说所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接,否则保留追究法律责任的权利.» 本文链接:http://www.jellythink.com/arch ...
- 深入浅出设计模式——工厂方法模式(Factory Method)
介绍在简单工厂模式中,我们提到,工厂方法模式是简单工厂模式的一个延伸,它属于Gof23中设计模式的创建型设计模式.它解决的仍然是软件设计中与创建对象有关的问题.它可以更好的处理客户的需求变化. 引入我 ...
随机推荐
- Unix系统编程()进程内存布局
每个进程所分配的内存由很多部分组成,通常称之为"段(segment)". 文本段包含了进程运行的程序机器语言指令.文本段具有只读属性,以防止进程通过错误指针意外修改自身指令. 因为 ...
- 16V554 的测试代码
//------------------------------------------------------------------------ #include "AT16C554 ...
- Oracle 错误:ORA-06413: Connection not open 解决办法
http://blog.csdn.net/neso520/article/details/6037411 ——————————————————————————————————————————————— ...
- CMake Error at cmake/boost.cmake:76 (MESSAGE):
编译mysql5.7.9的时候报错 CMake Error at cmake/boost.cmake:76 (MESSAGE): You can download it with -DDOWNLOAD ...
- Java 07 example
留下两个例子作为参考, 1. 追逐小方块的例子 2. HashMap 和 Iterator 的例子 Example one: import acm.graphics.*; import acm.pro ...
- 嵌入式开发之davinci--- 8148/8168/8127 中的二维图像处理内存tiler 铺瓷砖
http://blog.csdn.net/shanghaiqianlun/article/details/7619603
- 曲线学习PyQt5方案一
PyQt5官方网站没直接给出API,这个很操蛋啊. PtQt4官方网站有完整的API,C++版本的Qt5也能找到完整的API资料.由于Qt5的C++和Python3的类和函数实现应该是一致的,所以可以 ...
- 在mac下使用ppk文件ssh到远程主机
You can ssh directly from the Terminal on Mac, but you need to use a .PEM key rather than the putty ...
- Hive将txt、csv等文本文件导入hive表
1.将txt文本文件放置hdfs目录下 2.登录hive并进入到指定数据库 3.创建表 create external table if not exists fun_user_external ( ...
- 做一个WINDOWS下破解WIFI。不须要Linux抓包!
搬家了,没网了. 没有WIFI了! 想破解,只是没有Linux环境,不能抓包!破解! 于是自己动手开工. 在windows 下直接破解.貌似国内 还没看到.假设有了,那么请各位童鞋 提醒一下.赶急 要 ...