之前说了简单工厂设计模式如果增加一个新的运算的时候需要:增加一个具体的实现类,工厂类中增加一个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. [Git] Remove Files from Staging Before Committing

    If you've added files to the staging area (the Index) accidentally - you can remove them using git r ...

  2. LeetCode 491. Increasing Subsequences

    原题链接在这里:https://leetcode.com/problems/increasing-subsequences/ 题目: Given an integer array, your task ...

  3. linux MySQL5.7 rpm安装(转)

    删除旧包: # rpm -qa | grep -i mysql # rpm -ev mysql-libs-* --nodeps 安装rpm包: # rpm -ivh mysql-community-c ...

  4. win10系统绑定本地IP和mac地址

    第一步:找到自己的IP和mac地址 1.按着win键+R键,输入cmd(大小写都一样) 2.命令: ipconfig   /all              #查看所有地址 然后按“回车键” 3.这样 ...

  5. MySQL 练习题目 二刷 - 2019-11-4 5:55 am

    建表的过程 create table student( sid int not null primary key, sname ) not null, sborn date, ssex ) not n ...

  6. 5-网页,网站,微信公众号基础入门(配置网站--PHP配置上数据库)

    https://www.cnblogs.com/yangfengwu/p/11037653.html php和数据库打交道,这样整个网页就完美了,有了数据存储,交互,动态网页才完美 首先修改下php. ...

  7. Harbor基础

    harbor: Harbor是构建企业级私有docker镜像的仓库的开源解决方案,它是Docker Registry的更高级封装,它除了提供友好的Web UI界面,角色和用户权限管理,用户操作审计等功 ...

  8. lintcode-828. 字模式

    题目描述: 828.字模式 给定一个模式和一个字符串str,查找str是否遵循相同的模式.这里遵循的意思是一个完整的匹配,在一个字母的模式和一个非空的单词str之间有一个双向连接的模式对应. 样例 给 ...

  9. FZU Monthly-201906 tutorial

    FZU Monthly-201906 tutorial 题目(难度递增) easy easy-medium medium medium-hard hard 思维难度 AE B DG CF H A. X ...

  10. 【Gamma阶段】第三次Scrum Meeting

    冰多多团队-Gamma阶段第三次Scrum会议 工作情况 团队成员 已完成任务 待完成任务 卓培锦 修改可移动button以及button手感反馈优化 编辑器风格切换(夜间模式) 牛雅哲 添加优化算法 ...