工厂方法模式(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. Redis简单介绍

    redis简单介绍 Redis VS key-value缓存产品 Redis支持数据的持久化,能够将内存中的数据保持在磁盘中,重新启动的时候能够再次载入进行使用. Redis不只支持简单的key-va ...

  2. JSON 文件格式解析

    JSON 文件大致说明 JSON 文件你可以理解为就是一个字典文件. 格式为 { 索引:数据, 索引:{ 索引:数据, 索引:{ 索引:数据, 索引:数据 } } } 自己写一个 my.json { ...

  3. 理解vertical-align或“如何竖向居中”<转>

    在各种技术论坛里经常会有这样的问题提出,“我如何能将这个东西竖向居中?”这个问题通常会跟随着这样一句话,“我使用了 vertical-align:middle,但是不管用! ” 这个问题其实有三个层面 ...

  4. postgresql data数据目录路径迁移

    默认的数据库路径是/var/lib/pgsql/9.x/data 将现有的数据库文件全部拷贝到新的数据库路径下,然后重启 新建一个路径作为新的数据库数据路径,假如是/home/data sudo mk ...

  5. 【转】web测试技术经典案例(基础、全面)

    觉得有些内容还是挺实用的,就转了 1. 概述 随着web应用的增多,新的模式解决方案中以web为核心的应用也越来越多,很多公司各种应用的架构都以B/S及web应用为主,但是有关WEB测试方面的内容并没 ...

  6. ZooKeeper是以Fast Paxos算法为基础的

    ZooKeeper是以Fast Paxos算法为基础的,Paxos 算法存在活锁的问题,即当有多个proposer交错提交时,有可能互相排斥导致没有一个proposer能提交成功,而Fast Paxo ...

  7. JAVA学习资源网站

    中文java技术网——http://www.cn-java.com/ 灰狐动力(http://www.huihoo.com/)—— 该站点有许多的开源的项目的介绍和学习,涉及操作系统,数据库等许多方向 ...

  8. 【BZOJ】1688: [Usaco2005 Open]Disease Manangement 疾病管理(状压dp)

    http://www.lydsy.com/JudgeOnline/problem.php?id=1688 很水的状压.. 提交了很多次优化的,但是还是100msT_T #include <cst ...

  9. JavaScript 一、 ES6 声明变量,作用域理解

    // JavaScript/* * ========================================================= * * 编译原理 * 尽管通常将 JavaScr ...

  10. layui多选框

    多选下拉框:http://sun.faysunshine.com/layui/formSelects-v4/example/example_v4.html 1.下载formSelects-v4.1 2 ...