工厂方法模式(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)的更多相关文章

  1. Objective-C设计模式——工厂方法模式virtual constructor(对象创建)

    工厂方法模式 工厂方法模式可以控制对象的创建过程,屏蔽对象创建的细节,可以直接创建出我们所需要的已经配置好的对象. 工厂方法模式定义了创建方法的接口,让子类决定实例化哪一个类,工厂方法模式使得一个类的 ...

  2. JAVA设计模式--工厂方法模式

    工厂方法设计模式 抽象工厂角色: 这是工厂方法模式的核心,它与应用程序无关.是具体工厂角色必须实现的接口或者必须继承的父类.在java中它由抽象类或者接口来实现.具体工厂角色:它含有和具体业务逻辑有关 ...

  3. 我的Java设计模式-工厂方法模式

    女朋友dodo闹脾气,气势汹汹的说"我要吃雪糕".笔者心里啊乐滋滋的,一支雪糕就能哄回来,不亦乐乎?! 但是,雪糕买回来了,她竟然说"不想吃雪糕了,突然想吃披萨" ...

  4. Java设计模式—工厂方法模式&抽象工厂模式

    工厂方法模式与抽象工厂模式都是设计模式中重要而且常见的模式.       工厂方法模式:定义一个用于创建对象的接口,让子类决定实例化哪一个类.工厂方法使一个类的实例化延迟到其子类. 通用类图如下: 在 ...

  5. Java设计模式-工厂方法模式(Factory Method)

    工厂方法模式(Factory Method) 工厂模式适合:凡是出现了大量的产品需要创建,并且具有共同的接口时,可以通过工厂方法模式进行创建.在以下的三种模式中,第一种如果传入的字符串有误,不能正确创 ...

  6. Java设计模式---工厂方法模式(Factory-Method)

    一.普通工厂模式 建立一个工厂类,对实现了同一接口的一些类进行实例的创建 实例代码: 发送短信和邮件的例子,首先创建接口: public interface Sender { public void ...

  7. 4. 星际争霸之php设计模式--工厂方法模式

    题记==============================================================================本php设计模式专辑来源于博客(jymo ...

  8. C++设计模式——工厂方法模式

    本文版权归果冻说所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接,否则保留追究法律责任的权利.» 本文链接:http://www.jellythink.com/arch ...

  9. 深入浅出设计模式——工厂方法模式(Factory Method)

    介绍在简单工厂模式中,我们提到,工厂方法模式是简单工厂模式的一个延伸,它属于Gof23中设计模式的创建型设计模式.它解决的仍然是软件设计中与创建对象有关的问题.它可以更好的处理客户的需求变化. 引入我 ...

随机推荐

  1. JavaScript 框架 jQuery 的下载和安装

    jQuery 简介: jQuery 是一个 JavaScript 库. jQuery 极大地简化了 JavaScript 编程. jQuery 很容易学习. jQuery 下载: // 官网: htt ...

  2. 小贝_redis 高级应用-事务

    redis高级应用-事务 一.redis的事务 二.redis实现事务 三.redis事务问题 一.redis的事务 事务提供了一种"将多个命令打包,然后一次性.按顺序地运行"的机 ...

  3. Linux 高频工具快速教程

    全书分为三个部分: 第一部分为基础篇,介绍我们工作中常用的工具的高频用法: 第二部分为进阶篇,介绍的工具更多的适合程序员使用,分为程序构建.程序调试及程序优化: 第三部分是工具参考篇,主要介绍实用工具 ...

  4. Hadoop周边生态软件和简要工作原理(一)

    转自:http://www.it165.net/admin/html/201307/1531.html 基本都是在群里讨论的时候,别人问的入门问题,以后想到新的问题再补充进来.但是其实入门问题也很重要 ...

  5. Spring Boot可以离开Spring Cloud独立使用开发项目,但是Spring Cloud离不开Spring Boot,属于依赖的关系。

    Spring Boot 是 Spring 的一套快速配置脚手架,可以基于Spring Boot 快速开发单个微服务,Spring Cloud是一个基于Spring Boot实现的云应用开发工具:Spr ...

  6. OAuth2.0 介绍

    一.基本协议流程: (1) Client请求RO(Resource Owner)的授权:请求中一般包含:要访问的资源路径,操作类型,Client的身份等信息.(2) RO批准授权:并将“授权证据”发送 ...

  7. java---多线程及线程的概念

    如果对什么是线程.什么是进程仍存有疑惑,请先Google之,因为这两个概念不在本文的范围之内. 用多线程只有一个目的,那就是更好的利用cpu的资源,因为所有的多线程代码都可以用单线程来实现.说这个话其 ...

  8. 嵌入式驱动开发之uboot---uboot 中的常见命令参数参数

    Uboot相关命令介绍 bootm bootp cmp cp crc32 echo erase flinfo go minfo loadb loads mw 14mw 用指定的数据填充内存 15md ...

  9. YII2与Thinkphp整合阿里云OSS

    前言: 如果上传的文件都和网站程序源代码放在一起:那是有相当多的弊端的: 1:静态文件会占用大量带宽: 2:服务器的成本略高: 常规的做法是把php源代码放到一台服务器上:图片等静态文件放在另一台服务 ...

  10. hdu 1257 最少拦截系统(动态规划 / 贪心)

    最少拦截系统 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Subm ...