之前说了简单工厂设计模式如果增加一个新的运算的时候需要:增加一个具体的实现类,工厂类中增加一个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. svn服务器命令(转)

    *验证svn安装是否成功 #svnadmin --version *创建svn的数据仓库 #svnadmin create /data/svn/svndata/spms *启动svn服务 #svnse ...

  2. CT107D电路解析

    1.译码器: 其中,A.B.C为输入端, 对应关系如下: CBA  十进制    输出(低电平) 000      0           Y0 001      1           Y1 010 ...

  3. smartnic

    19年趋势: Intel® 2019网络技术研讨会圆满落幕 SANTOS: Flow and HQoS Acceleration Over DPDK Using Intel Programmable ...

  4. Linux常用命令简述--dirname与basename

    dirname 获取父目录 basename 显示最后的目录名或文件名 .dirname [root@liang ~]# dirname /etc/httpd/ /etc [root@liang ~] ...

  5. 在vb.net中使用委托:经理 和 员工

    现在开发的一个 vb.net系统,其中有两个窗体:alert窗体和 case窗体. 在alert窗体中列出了当前可以操作的若干个alert(可以理解为数据记录),用户可以选择将其中一个或几个alert ...

  6. 第一章 Electron介绍 | Electron in Action(中译)

    Github 官方地址 代表作: Visual Studio Code Atom - Code editor. Github开源的代码编辑器,Electron起源地 Visual Studio Cod ...

  7. 冰多多团队-第六次Scrum会议

    冰多多团队-第六次Scrum会议 工作情况 团队成员 已完成任务 待完成任务 zpj ASR bug修复 接入IAT模块 牛雅哲 完成语音识别->词典->termux的接口设计,熟悉了语法 ...

  8. c# async,await, 委托函数

    1.c#的异步实现,之前代码编写大都开几个线程. 现可以使用“async+await”方式实现异步(具体不详细介绍,暂且止在会用,仅仅是c#更新史上一个工具): static void Main(st ...

  9. js去除html标签样式

    params = params.replace(/<\/?.+?>/g,"").replace(/ /g,"");

  10. SpringMvc的 @Valid 拦截到的异常如何抛出

    SpringMvc中,校验参数可以使用 @Valid 注解,同时在相应的对象里使用 @NotBlank( message = "昵称不能为空")@NotNull( message ...