之前说了简单工厂设计模式如果增加一个新的运算的时候需要:增加一个具体的实现类,工厂类中增加一个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. MongoDB 部署复制集(副本集)

    部署MongoDB复制集(副本集)   环境 操作系统:Ubuntu 18.04 MongoDB: 4.0.3 服务器 首先部署3台服务器,1台主节点 + 2台从节点 3台服务器的内容ip分别是: 1 ...

  2. python函数 | 匿名函数lambda

    匿名函数:lambda 表达式.普通函数有且只有返回值的函数才能用匿名函数进行简化成一行函数. 匿名函数不单独使用,一般和内置函数结合使用.内置函数中,可加入函数的有min.max.sorted.ma ...

  3. Vuejs模板绑定

    一.Vue实例 ①el:指定被Vue管理的模板入口,网页中的DOM节点,但是不能使用body和html,必须是一个普通的HTML标签节点,一般是div ②data:数据驱动视图的数据,在data中初始 ...

  4. 9-网页,网站,微信公众号基础入门(使用PHP实现微信token验证)

    https://www.cnblogs.com/yangfengwu/p/11062422.html 这一节看怎么用PHP实现上一节的功能 关掉上一节的 学了这么久,忘了告诉大家怎么关闭程序了.... ...

  5. [RN] React Native :Error: Cannot find module 'asap/raw'

    今天在使用 react-native-dropdownmenus 的时候,安装没问题,但Link的时候 报: Error: Cannot find module 'asap/raw' 朋友们莫慌,一步 ...

  6. nginx 篇

    nginx 安装 下载必要组件 nginx下载地址 http://nginx.org/en/download.html pcre库下载地址,nginx需要 http://sourceforge.net ...

  7. bzoj3745: [Coci2015]Norma 分治,单调队列

    链接 bzoj 思路 首先\(\sum\limits_{i=1}^{n}\sum\limits_{j=1}^{n}\sum\limits_{k=i}^{j}max(a_k)\)可以用单调队列求解.参见 ...

  8. 如何实现大麦场在线选座 svg js

    本实例来源于此网站,内有Demo,可查看 <!DOCTYPE html> <html lang="en"> <head> <meta ch ...

  9. 利用iptables做端口转发

    需求背景: A与C不在同一网段无法直接访问,而A和B,C和B可以互通.现需要A借助B访问C的3306端口. 解决方案: 利用iptables配置规则,实现端口转发. 具体操作: 在B上开启端口转发功能 ...

  10. java 备用待迁移

    Java基础 2018年如何快速学Java 泛型就这么简单 注解就这么简单 Druid数据库连接池就是这么简单 Object对象你真理解了吗? JDK10都发布了,nio你了解多少? COW奶牛!Co ...