工厂方法?按图索骥!

2023-12-30 11:12
文章标签 方法 工厂 按图索骥

本文主要是介绍工厂方法?按图索骥!,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

前言

还记得在第3节的简单工厂模式,我们实现了一个简易计算器。简单工厂模式的最大优点在于工厂类中包含了必要的逻辑判断,根据客户端的选择条件动态实例化相关类,去除了与具体运算类的依赖

但其问题也就在这里,如果要加一个‘求余’运算符的功能,我们需要在运算工厂类的方法里加‘Case’的分支条件的,那这就必然涉及到修改原有的类?这就等于说,我们不但对扩展开放了,对修改也开放了,就违背了开放-封闭原则。那有没有一种方法既可以实现简单工厂方法的作用,又能够避免修改已有的类呢?

有的,那就是我们之后将介绍的工厂方法模式。

什么是工厂方法模式?

工厂方法模式(Factory method),定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。

在之前的简单工厂方法实现中,**工厂类与分支耦合(如果新增一种运算符,需要在工厂类中添加一个分支)。既然工厂类与分支耦合,那么根据依赖倒置原则,我们可以将工厂类抽象成一个接口,**该接口只有一个方法,那就是创建对应的运算符,**通过这种方式,将两者进行解耦合,**其UML类图如下。

img

工厂方法实现

我们来看看如果使用工厂方法,应该如何实现之前的简易计算器。

再次回顾一下计算器的要求:“实现一个计算器程序,要求输入两个数和运算符号,得到结果,暂时实现加减乘除即可,考虑之后的运算符扩充。”基于工厂方法,我们可以将UML类图设计成这样

img

运算符类

运算符类跟第3节相同,在此不再赘述。

package com.whitedew.factorymethod;//操作类
public class Operation {//子类能继承父类的所有属性,但父类若为私有属性,子类只是拥有,无法使用。//因此使用protected修饰protected double numberA = 0;protected double numberB = 0;public double getNumberA() {return numberA;}public void setNumberA(double numberA) {this.numberA = numberA;}public double getNumberB() {return numberB;}public void setNumberB(double numberB) {this.numberB = numberB;}public double getResult() {double result = 0;return result;}
}

具体运算类

同第3节的代码,此处省略。

工厂接口

所有的具体运算类都需要一个工厂来实现这个接口。

public interface IFactory {Operation createOperation();
}

运算类的工厂

所有的运算类都需要一个对应的工厂,来实现上面的那个工厂接口,并且由这个工厂实例来创建不同的产品实例。以乘法为例:

public class MultiFactory implements IFactory {@Overridepublic Operation createOperation() {return new OperationMulti();}
}

计算器的客户端

由于switch case已经从工厂类中移除,于是有关运算符的判断就需要放到客户端来实现了。

package com.whitedew.factorymethod;
public class CalculatorClient {public static void main(String[] args) {IFactory iFactory = null;int numberA = 0;int numberB = 0;String operationStr = null;Scanner scanner = new Scanner(System.in);System.out.print("请输入数字A : ");// 判断是否还有输入if (scanner.hasNext()) {numberA = scanner.nextInt();System.out.println("输入的数据为:" + numberA);}System.out.print("请选择运算符(+-*/): ");// 判断是否还有输入if (scanner.hasNext()) {operationStr = scanner.next();System.out.println("选择的运算符为:" + operationStr);}System.out.print("请输入数字B : ");// 判断是否还有输入if (scanner.hasNext()) {numberB = scanner.nextInt();System.out.println("输入的数据为:" + numberB);}switch (operationStr) {case "+":iFactory = new AddFactory();break;case "-":iFactory = new SubFactory();break;case "*":iFactory = new MultiFactory();break;case "/":iFactory = new DivFactory();break;default:System.out.println("操作符为空");System.exit(0);}Operation operation = iFactory.createOperation();operation.setNumberA(numberA);operation.setNumberB(numberB);double result = operation.getResult();System.out.println("结果为" + numberA + operationStr + numberB + "=" + result);}
}

结果

运算结果如下,3*5:

img

总结

从上面的例子可以看出,工厂方法模式是简单工厂模式的进一步抽象和推广。由于使用了多态性,工厂方法模式保持了简单工厂模式的优点,而且克服了它的缺点(即违背开放-封闭原则)

但这种方法也带来了另外一个弊端:每加一个产品,就需要加一个产品工厂的类,增加了额外的开发量,但是这个缺点在大部分时候都是可以接收的。同时,由于判断逻辑放在了客户端,增加了客户端的代码开发量,有关这一点,在Java语言中,可以通过抽象工厂模式+反射来实现,详见第5节抽象工厂模式。

参考资料

《大话设计模式》

代码实现

这篇关于工厂方法?按图索骥!的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/552658

相关文章

MySQL 表空却 ibd 文件过大的问题及解决方法

《MySQL表空却ibd文件过大的问题及解决方法》本文给大家介绍MySQL表空却ibd文件过大的问题及解决方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考... 目录一、问题背景:表空却 “吃满” 磁盘的怪事二、问题复现:一步步编程还原异常场景1. 准备测试源表与数据

python 线程池顺序执行的方法实现

《python线程池顺序执行的方法实现》在Python中,线程池默认是并发执行任务的,但若需要实现任务的顺序执行,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋... 目录方案一:强制单线程(伪顺序执行)方案二:按提交顺序获取结果方案三:任务间依赖控制方案四:队列顺序消

SpringBoot通过main方法启动web项目实践

《SpringBoot通过main方法启动web项目实践》SpringBoot通过SpringApplication.run()启动Web项目,自动推断应用类型,加载初始化器与监听器,配置Spring... 目录1. 启动入口:SpringApplication.run()2. SpringApplicat

使用Java读取本地文件并转换为MultipartFile对象的方法

《使用Java读取本地文件并转换为MultipartFile对象的方法》在许多JavaWeb应用中,我们经常会遇到将本地文件上传至服务器或其他系统的需求,在这种场景下,MultipartFile对象非... 目录1. 基本需求2. 自定义 MultipartFile 类3. 实现代码4. 代码解析5. 自定

Python文本相似度计算的方法大全

《Python文本相似度计算的方法大全》文本相似度是指两个文本在内容、结构或语义上的相近程度,通常用0到1之间的数值表示,0表示完全不同,1表示完全相同,本文将深入解析多种文本相似度计算方法,帮助您选... 目录前言什么是文本相似度?1. Levenshtein 距离(编辑距离)核心公式实现示例2. Jac

C#高效实现Word文档内容查找与替换的6种方法

《C#高效实现Word文档内容查找与替换的6种方法》在日常文档处理工作中,尤其是面对大型Word文档时,手动查找、替换文本往往既耗时又容易出错,本文整理了C#查找与替换Word内容的6种方法,大家可以... 目录环境准备方法一:查找文本并替换为新文本方法二:使用正则表达式查找并替换文本方法三:将文本替换为图

SQL Server 查询数据库及数据文件大小的方法

《SQLServer查询数据库及数据文件大小的方法》文章介绍了查询数据库大小的SQL方法及存储过程实现,涵盖当前数据库、所有数据库的总大小及文件明细,本文结合实例代码给大家介绍的非常详细,感兴趣的... 目录1. 直接使用SQL1.1 查询当前数据库大小1.2 查询所有数据库的大小1.3 查询每个数据库的详

Java实现本地缓存的四种方法实现与对比

《Java实现本地缓存的四种方法实现与对比》本地缓存的优点就是速度非常快,没有网络消耗,本地缓存比如caffine,guavacache这些都是比较常用的,下面我们来看看这四种缓存的具体实现吧... 目录1、HashMap2、Guava Cache3、Caffeine4、Encache本地缓存比如 caff

Java 中编码与解码的具体实现方法

《Java中编码与解码的具体实现方法》在Java中,字符编码与解码是处理数据的重要组成部分,正确的编码和解码可以确保字符数据在存储、传输、读取时不会出现乱码,本文将详细介绍Java中字符编码与解码的... 目录Java 中编码与解码的实现详解1. 什么是字符编码与解码?1.1 字符编码(Encoding)1

Python Flask实现定时任务的不同方法详解

《PythonFlask实现定时任务的不同方法详解》在Flask中实现定时任务,最常用的方法是使用APScheduler库,本文将提供一个完整的解决方案,有需要的小伙伴可以跟随小编一起学习一下... 目录完js整实现方案代码解释1. 依赖安装2. 核心组件3. 任务类型4. 任务管理5. 持久化存储生产环境