工厂方法模式(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. JVM调优浅谈(转)

    1.数据类型 java虚拟机中,数据类型可以分为两类:基本类型和引用类型.基本类型的变量保存原始值,即:它代表的值就是数值本身,而引用类型的变量保存引用值.“引用值”代表了某个对象的引用,而不是对象本 ...

  2. 巨头们的GitHub仓库整理

    1.Google >1.Google >https://github.com/google >2.Google Samples https://github.com/googlesa ...

  3. 07 Test结构

    Test 有多种实现方式, [ 等价于 test, 并且 [ 是一个内建命令, 效率很高 另外, [[]] 也是测试, [[]]结构比bash[]更灵活, 这是一个扩展test命令, 从ksh88继承 ...

  4. 回文树(统计所有回文串的个数) - MCCME 1750 Подпалиндромы

    Подпалиндромы Problem's Link: http://informatics.mccme.ru//mod/statements/view.php?chapterid=1750# M ...

  5. [mysql] Navicat for mysql_导入导出表结构

    应用场景: 当 ① 由于权限控制,远程数据库在外网不能访问 ② 远程数据库连接和查询比较慢,影响工作效率 这时,可以将远程数据库的表结构和已有数据COPY到本地的mysql服务器来进行开发. 只需要将 ...

  6. C++ 指针引用

    //指针引用 #include<iostream> using namespace std; struct Teacher{ ]; int age; }; int InitA(Teache ...

  7. tp 批量转码

    读取王正东成功,然后把乱码一条一条的改回来... 专门针对mssql数据库的!!!

  8. mybatis 的动态sql语句是基于OGNL表达式的。

    mybatis 的动态sql语句是基于OGNL表达式的.可以方便的在 sql 语句中实现某些逻辑. 总体说来mybatis 动态SQL 语句主要有以下几类:1. if 语句 (简单的条件判断)2. c ...

  9. javascript new Date()函数在不同浏览器上返回不同的值

    今天是2015年3月16日,在IE 6 上new Date()返回给后台server的字符串格式为 "Mon Mar 16  00:00:00 UTC 0800 2015",而在f ...

  10. Spring_day01--课程安排_Spring概念_IOC操作&IOC底层原理&入门案例_配置文件没有提示问题

    Spring_day01 Spring课程安排 今天内容介绍 Spring概念 Spring的ioc操作 IOC底层原理 IOC入门案例 配置文件没有提示问题 Spring的bean管理(xml方式) ...