之前说了简单工厂设计模式如果增加一个新的运算的时候需要:增加一个具体的实现类,工厂类中增加一个case分支。也就是说我们不但对扩展开发了,也对修改开放了,违背了开闭原则。当然如果工厂类采用反射的话不存在这个问题。(实际工作中工厂类使用反射也是最常见的运用方式)

  工厂方法模式(多态性工厂或虚拟构造子模式):定义一个创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类中。

  工厂方法模式实现时,客户端需要决定实例化哪一个工厂来实现运算进行,选择判断的问题还是存在的,也就是说,工厂方法把简单工厂的内部逻辑判断移到了客户端代码来进行。你要想加功能,本来是要改工厂类的,现在变成改客户端。解决简单工厂的工厂类中复杂的创建具体对象的业务逻辑判断,如果工厂类采用反射创建对象则不需要解决这种问题。

  还是以运算类为例,把工厂抽象出一个接口,这个接口只有一个方法,就是创建抽象产品的工厂方法。然后所有的要生产具体类的工厂去实现这个接口。这样,一个简单工厂模式的工厂类就变成了一个工厂抽象接口和多个具体生成对象的工厂。

  类图如下:

上面设计到的角色解释:

抽象工厂(OperationFactory)角色:担任这个角色的是工厂方法模式的核心,任何在模式中创建对象的工厂类必须实现这个接口。实际工作中,这个角色也常常使用抽象类实现。(或者使用接口+抽象类更好的封装)

具体工厂(OperationAddFactory、OperationSubFactory。。。)角色:担任这个角色的是实现了抽象工厂接口的具体JAVA类。具体工厂角色含有与业务密切相关的逻辑,并且受到使用者的调用以创建运算类。

抽象运算(Operation)角色:工厂方法模式所创建的对象的超类,也就是所有运算类的共同父类或共同拥有的接口。实际工作中,这个角色也常常使用抽象类实现。(或者使用接口+抽象类更好的封装,如上就运用抽象类+接口+继承)

具体运算(OperationAdd、OperationSub。。。)角色:这个角色实现了实现了抽象运算所声明的接口,工厂方法模式所创建的每一个对象都是某个具体运算角色的实例。

代码如下:

运算类相关代码

package cn.qlq;

public interface Operation {

    String operateType();

    Number operate(Number... nums);
}
package cn.qlq;

public abstract class AbstractOperation implements Operation {

    @Override
public Number operate(Number... nums) {
if (nums == null || nums.length == 0) {
System.out.println("非法参数");
return 0;
} System.out.println("参数验证通过");
return doOperate(nums);
} public abstract Number doOperate(Number[] nums);
}
package cn.qlq;

public class OperationAdd extends AbstractOperation {

    @Override
public String operateType() {
return "OperationAdd";
} @Override
public Number doOperate(Number... nums) {
Number result = 0;
for (Number number : nums) {
result = result.doubleValue() + number.doubleValue();
} return result;
} }
package cn.qlq;

public class OperationSub extends AbstractOperation {

    @Override
public String operateType() {
return "OperationSub";
} @Override
public Number doOperate(Number... nums) {
Number result = nums[0];
for (int i = 0, length_1 = nums.length; i < length_1; i++) {
if (i == 0) {
continue;
}
result = result.doubleValue() - nums[i].doubleValue();
} return result;
} }
package cn.qlq;

public class OperationMul extends AbstractOperation {

    @Override
public String operateType() {
return "OperationMul";
} @Override
public Number doOperate(Number... nums) {
Number result = nums[0];
for (int i = 0, length_1 = nums.length; i < length_1; i++) {
if (i == 0) {
continue;
}
result = result.doubleValue() * nums[i].doubleValue();
} return result;
} }
package cn.qlq;

public class OperationDiv extends AbstractOperation {

    @Override
public String operateType() {
return "OperationDiv";
} @Override
public Number doOperate(Number... nums) {
Number result = nums[0];
for (int i = 0, length_1 = nums.length; i < length_1; i++) {
if (i == 0) {
continue;
}
result = result.doubleValue() / nums[i].doubleValue();
} return result;
} }

工厂类相关代码:

package cn.qlq;

public interface OperationFactory {

    /**
*
* @param type
* @return
*/
Operation generateOperation(String type);
}
package cn.qlq;

public class OperationAddFactory implements OperationFactory {

    @Override
public Operation generateOperation(String type) {
return new OperationAdd();
} }
package cn.qlq;

public class OperationSubFactory implements OperationFactory {

    @Override
public Operation generateOperation(String type) {
return new OperationSub();
} }
package cn.qlq;

public class OperationMulFactory implements OperationFactory {

    @Override
public Operation generateOperation(String type) {
return new OperationMul();
} }
package cn.qlq;

public class OperationDivFactory implements OperationFactory {

    @Override
public Operation generateOperation(String type) {
return new OperationDiv();
} }

客户端测试代码:

package cn.qlq;

public class MainClass {

    public static void main(String[] args) {
// 客户端判断使用哪一种工厂
String operationType = "OperationAdd";
OperationFactory operationFactory = new OperationAddFactory(); // 生成具体的运算类
Operation operation = operationFactory.generateOperation(operationType);
System.out.println(operation.operateType());
Number operate = operation.operate(1, 2);
System.out.println(operate);
} }

  工厂模式可以理解为将原来简单工厂的判断创建哪一个具体产品的逻辑交给客户端,客户端需要判断采用哪一个工厂。

      上面工厂类的generateOperation方法传入String类型的参数也是有用的,比如:对于减法运算,有时候第一个减后面所有的数,有时候最后一个减前面所有的数。这时候设计到的两种运算规则就可以通过参数类型创建不同的运算类,如下:

(1)增加最后一个数减前面数的运算类:

package cn.qlq;

public class OperationSubReverse extends AbstractOperation {

    @Override
public String operateType() {
return "OperationSubReverse";
} @Override
public Number doOperate(Number... nums) {
int length_1 = nums.length;
Number result = nums[length_1 - 1];
for (int i = 0; i < length_1; i++) {
if (i == length_1 - 1) {
continue;
}
result = result.doubleValue() - nums[i].doubleValue();
} return result;
} }

(2)重写减法工厂类

package cn.qlq;

public class OperationSubFactory implements OperationFactory {

    @Override
public Operation generateOperation(String type) {
if ("OperationSubReverse".equals(type)) {
return new OperationSubReverse();
} else if ("OperationSub".equals(type)) {
return new OperationSub();
} return null;
} }

工厂方法模式和简单工厂方法模式:

  工厂方法模式和简单工厂模式在结构上的不同很明显。工厂方法模式的核心是一个抽象工厂类,而简单工厂模式把核心放在一个具体类上。
  工厂方法模式退化后可以变得很像简单工厂模式。设想如果非常确定一个系统只需要一个具体工厂类,那么不妨把抽象工厂类合并到具体工厂类中去。由于只有一个具体工厂类,所以不妨将工厂方法改为静态方法,这时候就得到了简单工厂模式。

工厂方法(FactoryMethod)模式的更多相关文章

  1. 设计模式之工厂方法(FactoryMethod)模式

    在五大设计原则的基础上经过GOF(四人组)的总结,得出了23种经典设计模式,其中分为三大类:创建型(5种).结构型(7种).行为型(11种).今天对创建型中的工厂方法(FactoryMethod)模式 ...

  2. 一天一个设计模式——工厂方法(FactoryMethod)模式

    一.模式说明 在前一个模板方法(Template Method)模式中,父类定义了处理流程,而流程中用到的方法交给子类去实现.类似的,在工厂方法模式中,父类决定如何生成实例,但并不决定所要生成的具体类 ...

  3. 工厂方法FactoryMethod 初步学习笔记

    一,意图   定义一个用于创建对象的接口,让子类决定实例化哪一个类.工厂方法使一个类的实例化延迟到其子类. 二,别名   虚构造器 Virtual Constructor 三,适用性 当一个类不知道它 ...

  4. factory工厂模式之工厂方法FactoryMethod

    工厂方法(Factory Method) * 工厂方法把不同的产品放在实现了工厂接口的不同工厂类(FactoryAImpl,FactoryBImpl...)里面, * 这样就算其中一个工厂类出了问题, ...

  5. 【设计模式】——工厂方法FactoryMethod

    前言:[模式总览]——————————by xingoo 模式意图 工厂方法在MVC中应用的很广泛. 工厂方法意在分离产品与创建的两个层次,使用户在一个工厂池中可以选择自己想要使用的产品,而忽略其创建 ...

  6. spring中bean标签factory-method和factory-bean)详解工厂方法(factory-method和factory-bean)

    转自:http://blog.sina.com.cn/s/blog_6d3c1ec601019f3j.html A.factory-method The name of a factory metho ...

  7. 设计模式——从工厂方法模式到 IOC/DI思想

    回顾简单工厂 回顾:从接口的角度去理解简单工厂模式 前面说到了简单工厂的本质是选择实现,说白了是由一个专门的类去负责生产我们所需要的对象,从而将对象的创建从代码中剥离出来,实现松耦合.我们来看一个例子 ...

  8. 抽象工厂(Abstract Factory),工厂方法(Factory Method),单例模式(Singleton Pattern)

    在谈工厂之前,先阐述一个观点:那就是在实际程序设计中,为了设计灵活的多态代码,代码中尽量不使用new去实例化一个对象,那么不使用new去实例化对象,剩下可用的方法就可以选择使用工厂方法,原型复制等去实 ...

  9. 工厂方法在Spring源码中的运用

    我们都知道Spring中IOC是使用的工厂模式,但是对于实现细节就一知半解了,今天这篇文章就带大家解读Spring中是如何使用工厂模式的. 在上篇文章中我们懂了什么是工厂模式,这篇文章就带着学过的概念 ...

随机推荐

  1. 大文件断点续传插件webupload插件

    java两台服务器之间,大文件上传(续传),采用了Socket通信机制以及JavaIO流两个技术点,具体思路如下: 实现思路: 1.服:利用ServerSocket搭建服务器,开启相应端口,进行长连接 ...

  2. 超实用文件监控多线程FTP上传工具

    这是自己很久以前写的一个多线程FTP 上传工具,支持多账户,自定义线程数,自定义文件监控目录,可用做文件发布使用,非常实用,今天有小伙伴问起,现分享出来: using System; using Sy ...

  3. Redis之eval+lua实现初步

    目录 目录 1 1. 前言 1 2. 执行方式 1 3. 执行过程 3 4. 使用原则 3 1. 前言 Redis的实现保证eval的执行是原子的,即使eval执行的lua超时,Redis也不会自动终 ...

  4. 05-树9 Huffman Codes (30 分)

    In 1953, David A. Huffman published his paper "A Method for the Construction of Minimum-Redunda ...

  5. tomcat做成Windows自启动服务

    一.下载Tomcat 下载Windows版本的tomcat,一般是以zip结尾的包,免安装的包,而Linux包虽然解压可以运行,但是缺少service.bat关键文件,无法做成服务形式 下载网站: h ...

  6. UDF——计算壁面边界合力矩(旋转机械)

  7. 【Beta阶段】第十次Scrum Meeting

    每日任务内容 队员 昨日完成任务 明日要完成的任务 张圆宁 #69 后端文档https://github.com/rRetr0Git/rateMyCourse/issues/69 网站测试.推广 牛宇 ...

  8. [Beta]Scrum Meeting#6

    github 本次会议项目由PM召开,时间为5月11日晚上10点30分 时长15分钟 任务表格 人员 昨日工作 下一步工作 木鬼 撰写博客整理文档 撰写博客整理文档 swoip 改进界面 为适应新功能 ...

  9. js - true和false

    JavaScript的true和false什么时候会出现,如何优雅的写判断条件? 以下条件为false,也可称为“falsy” - > 虚值 if (false) if (null) if (u ...

  10. Evolutionary approaches towards AI: past, present, and future

    Evolutionary approaches towards AI: past, present, and future 2019-10-06 07:28:13 This blog is from: ...