当前位置: 首页 > news >正文

设计模式-第6章(工厂模式)

工厂模式

  • 简单工厂实现
  • 工厂模式实现
  • 简单工厂 VS 工厂方法
  • 商场收银程序再再升级(简单工厂+策略+装饰+工厂方法)
  • 工厂方法模式总结

简单工厂实现

在这里插入图片描述
在简单工厂类中,通过不同的运算符,创建具体的运算类。

public class OperationFactory {public static Operation createOperate(String operate){Operation oper = null;switch (operate) {case "+":oper = new Add();break;case "-":oper = new Sub();break;case "*":oper = new Mul();break;case "/":oper = new Div();break;}return oper;}
}

工厂模式实现

在这里插入图片描述
工厂类

// 工厂接口
public interface IFactory {public Operation createOperation();   
}
//减法工厂
public class SubFactory implements IFactory {public Operation createOperation(){return new Sub();}
}
//加法工厂
public class AddFactory implements IFactory {public Operation createOperation(){return new Add();}
}
//除法工厂
public class DivFactory implements IFactory {public Operation createOperation(){return new Div();}
}
//乘法工厂
public class MulFactory implements IFactory {public Operation createOperation(){return new Mul();}
}

运算类

// 抽象运算类
public abstract class Operation {public double getResult(double numberA, double numberB){return 0d;}
}
// 减法运算类
public class Sub extends Operation {public double getResult(double numberA, double numberB){return numberA - numberB;}
}
// 加法运算类
public class Add extends Operation {public double getResult(double numberA, double numberB){return numberA + numberB;}
}
// 除法运算类
public class Div extends Operation {public double getResult(double numberA, double numberB){if (numberB == 0){System.out.println("除数不能为0");throw new ArithmeticException();}return numberA / numberB;}
}
// 乘法运算类
public class Mul extends Operation {public double getResult(double numberA, double numberB){return numberA * numberB;}
}

运算工厂

public class OperationFactory {public static Operation createOperate(String operate){Operation oper = null;IFactory factory = null;switch (operate) {case "+":// 隐藏了具体运算类的创建过程factory = new AddFactory();break;case "-":factory = new SubFactory();break;case "*":factory = new MulFactory();break;case "/":factory = new DivFactory();break;}oper = factory.createOperation();  return oper;}
}

客户端

public class Test {public static void main(String[] args){System.out.println("**********************************************");		System.out.println("《大话设计模式》代码样例");System.out.println();		try {Scanner sc = new Scanner(System.in);System.out.println("请输入数字A:");	double numberA = Double.parseDouble(sc.nextLine());System.out.println("请选择运算符号(+、-、*、/):");	String strOperate = sc.nextLine();System.out.println("请输入数字B:");	double numberB = Double.parseDouble(sc.nextLine());Operation oper = OperationFactory.createOperate(strOperate);double result = oper.getResult(numberA,numberB);System.out.println("结果是:"+result);	}catch(Exception e){System.out.println("您的输入有错:"+e.toString());	}System.out.println();System.out.println("**********************************************");}
}

简单工厂 VS 工厂方法

简单工厂模式的最大优点在于工厂类中包含必要的逻辑判断,根据客户端的选择条件动态实例化相关的类,对于客户端来说,去除了与具体产品的依赖。

在简单工厂中,由于每次增加运算类,都需要在工厂类中增加Case分支条件。这对于工厂类来说,不是一个好办法,频繁的进行修改,违反了开放-封闭原则。

尽量将长的代码分派切割成小段,再将每一小段封装起来,减少每段代码之间的耦合,这样风险就分散了,需要修改或扩展的难度就降低了。

可以将加减乘除基础的运算类,由一个基础运算工厂进行创建,增加的指数,对数运算类,再增加一个高级运算工厂类进行创建。就不会影响基础运算类的部分。
在这里插入图片描述

// 抽象工厂接口
public interface IFactory {public Operation createOperation(String operType);
}
//基础运算工厂
public class FactoryBasic implements IFactory {public Operation createOperation(String operType){Operation oper = null;switch (operType) {case "+":oper = new Add();break;case "-":oper = new Sub();break;case "*":oper = new Mul();break;case "/":oper = new Div();break;}  return oper;}
}
//高级运算工厂
public class FactoryAdvanced implements IFactory {public Operation createOperation(String operType){Operation oper = null;switch (operType) {case "pow":oper = new Pow();//指数运算类实例break;case "log":oper = new Log();//对数运算类实例break;//此处可扩展其他高级运算类的实例化,但修改//当前工厂类不会影响到基础运算工厂类}return oper;}    
}

运算工厂类

public class OperationFactory {public static Operation createOperate(String operate){Operation oper = null;IFactory factory = null;switch (operate) {case "+":case "-":case "*":case "/"://基础运算工厂实例factory=new FactoryBasic();break;case "pow":case "log"://高级运算工厂实例factory=new FactoryAdvanced();break;}  //利用多态返回实际的运算类实例oper = factory.createOperation(operate);return oper;}
}

客户端

public class Test {public static void main(String[] args){System.out.println("**********************************************");		System.out.println("《大话设计模式》代码样例");System.out.println();		try {Scanner sc = new Scanner(System.in);System.out.println("请输入数字A:");	double numberA = Double.parseDouble(sc.nextLine());System.out.println("请选择运算符号(+、-、*、/):");	String strOperate = sc.nextLine();System.out.println("请输入数字B:");	double numberB = Double.parseDouble(sc.nextLine());Operation oper = OperationFactory.createOperate(strOperate);double result = oper.getResult(numberA,numberB);System.out.println("结果是:"+result);	}catch(Exception e){System.out.println("您的输入有错:"+e.toString());	}System.out.println();System.out.println("**********************************************");}
}

在新的 OperationFactory类已经不存在实例化运算子类的代码,在这个代码里,全是接口和具体工厂类。将实例化的过程放到了子类工厂中。这就是针对接口编程,不要对实现编程。

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

工厂方法模式结构图
在这里插入图片描述

商场收银程序再再升级(简单工厂+策略+装饰+工厂方法)

在上一版代码中,通过简单工厂,对于不同的条件,生成具体的收费策略类。可以使用工厂方法模式替代简单工厂。
在这里插入图片描述
对于不同的收费策略,可以分为两类,先打折后满减和先满减后打折。

// 工厂接口
public interface IFactory {public ISale createSalesModel(); //创建销售模式
}
//先打折再满减类
public class CashRebateReturnFactory implements IFactory {private double moneyRebate = 1d;private double moneyCondition = 0d;private double moneyReturn = 0d;public CashRebateReturnFactory(double moneyRebate,double moneyCondition,double moneyReturn){this.moneyRebate = moneyRebate;this.moneyCondition = moneyCondition;this.moneyReturn = moneyReturn;}//先打x折,再满m返npublic ISale createSalesModel(){CashNormal cn = new CashNormal();CashReturn cr1 = new CashReturn(this.moneyCondition,this.moneyReturn); CashRebate cr2 = new CashRebate(this.moneyRebate);cr1.decorate(cn);   //用满m返n算法包装基本的原价算法cr2.decorate(cr1);  //打x折算法装饰满m返n算法return cr2;         //将包装好的算法组合返回}    
}
//先满减再打折类
public class CashReturnRebateFactory implements IFactory {private double moneyRebate = 1d;private double moneyCondition = 0d;private double moneyReturn = 0d;public CashReturnRebateFactory(double moneyRebate,double moneyCondition,double moneyReturn){this.moneyRebate = moneyRebate;this.moneyCondition = moneyCondition;this.moneyReturn = moneyReturn;}//先满m返n,再打x折public ISale createSalesModel(){CashNormal cn2 = new CashNormal();CashRebate cr3 = new CashRebate(this.moneyRebate);CashReturn cr4 = new CashReturn(this.moneyCondition,this.moneyReturn); cr3.decorate(cn2);  //用打x折算法包装基本的原价算法cr4.decorate(cr3);  //满m返n算法装饰打x折算法return cr4;         //将包装好的算法组合返回}    
}
// 收费接口
public interface ISale {public double acceptCash(double price,int num);
}
public class CashNormal implements ISale {//正常收费,原价返回public double acceptCash(double price,int num){return price * num; }    
}
public class CashSuper implements ISale {protected ISale component;//装饰对象public void decorate(ISale component) {this.component = component;}public double acceptCash(double price,int num){if (this.component != null){//若装饰对象存在,则执行装饰的算法运算return this.component.acceptCash(price,num);    }else return 0d;}
}
public class CashRebate extends CashSuper {private double moneyRebate = 1d;//打折收费。初始化时必需输入折扣率。八折就输入0.8public CashRebate(double moneyRebate){this.moneyRebate = moneyRebate;}//计算收费时需要在原价基础上乘以折扣率public double acceptCash(double price,int num){double result = price * num * this.moneyRebate;return super.acceptCash(result,1);}
}
public class CashReturn extends CashSuper {private double moneyCondition = 0d; //返利条件private double moneyReturn = 0d;    //返利值//返利收费。初始化时需要输入返利条件和返利值。//比如“满300返100”,就是moneyCondition=300,moneyReturn=100public CashReturn(double moneyCondition,double moneyReturn){this.moneyCondition = moneyCondition;this.moneyReturn = moneyReturn;}//计算收费时,当达到返利条件,就原价减去返利值public double acceptCash(double price,int num){double result = price * num;if (moneyCondition>0 && result >= moneyCondition)result = result - Math.floor(result / moneyCondition) * moneyReturn; return super.acceptCash(result,1);   }
}

在 CashContext 中,使用具体的工厂来得到不同的收费策略类。

public class CashContext {private ISale cs;   //声明一个ISale接口对象//通过构造方法,传入具体的收费策略public CashContext(int cashType){IFactory fs=null;switch(cashType) {case 1://原价fs = new CashRebateReturnFactory(1d,0d,0d);break;case 2://8折fs = new CashRebateReturnFactory(0.8d,0d,0d);break;case 3://7折fs = new CashRebateReturnFactory(0.7d,0d,0d);break;case 4://300100fs = new CashRebateReturnFactory(1,300d,100d);break;case 5://先打8,再满300100fs = new CashRebateReturnFactory(0.8d,300d,100d);break;case 6://先满20050,再打7折fs = new CashReturnRebateFactory(0.7d,200d,50d);break;}this.cs = fs.createSalesModel();}public double getResult(double price,int num){//根据收费策略的不同,获得计算结果return this.cs.acceptCash(price,num);}    
}

客户端

public class Test {public static void main(String[] args){System.out.println("**********************************************");		System.out.println("《大话设计模式》代码样例");System.out.println();		int discount = 0; 		//商品折扣模式double price = 0d; 		//商品单价int num = 0;			//商品购买数量double totalPrices = 0d;//当前商品合计费用double total = 0d;		//总计所有商品费用Scanner sc = new Scanner(System.in);do {System.out.println("商品折扣模式如下:");	System.out.println("1.正常收费");	System.out.println("2.打八折");	System.out.println("3.打七折");	System.out.println("4.满300送100");	System.out.println("5.先打8折,再满300送100");	System.out.println("6.先满200送50,再打7折");	System.out.println("请输入商品折扣模式:");	discount = Integer.parseInt(sc.nextLine());System.out.println("请输入商品单价:");	price = Double.parseDouble(sc.nextLine());System.out.println("请输入商品数量:");	num = Integer.parseInt(sc.nextLine());System.out.println();	if (price>0 && num>0){//根据用户输入,将对应的策略对象作为参数传入CashContext对象中CashContext cc = new CashContext(discount);//通过Context的getResult方法的调用,可以得到收取费用的结果//让具体算法与客户进行了隔离totalPrices = cc.getResult(price,num);total = total + totalPrices;System.out.println();	System.out.println("单价:"+ price + "元 数量:"+ num +" 合计:"+ totalPrices +"元");	System.out.println();System.out.println("总计:"+ total+"元");	System.out.println();}} while(price>0 && num>0);System.out.println();System.out.println("**********************************************");}
}

工厂方法模式总结

工厂方法克服了简单工厂违背开放-封闭原则的缺点,又保持封装对象创建过程的优点。
工厂方法模式是简单工厂模式的进一步抽象和推广。是对获取对象过程的进一步抽象。

工厂方法模式的好处

  • 对于复杂的参数的构造对象,可以很好地对外层屏蔽代码的复杂性。
  • 很好的解耦能力,针对接口编程,屏蔽了细节。

相关文章:

设计模式-第6章(工厂模式)

工厂模式简单工厂实现工厂模式实现简单工厂 VS 工厂方法商场收银程序再再升级(简单工厂策略装饰工厂方法)工厂方法模式总结简单工厂实现 在简单工厂类中,通过不同的运算符,创建具体的运算类。 public class OperationFactory {pu…...

【JAVA】线程和进程

🏆今日学习目标:线程和进程 😃创作者:颜颜yan_ ✨个人主页:颜颜yan_的个人主页 ⏰本期期数:第三期 🎉专栏系列:JAVA 线程和进程前言一、进程与线程1.进程2.线程二、线程的创建2.1 继…...

移动app安全测试工具好物分享

移动互联网时代,我们的生活和工作深受移动app的影响。随着移动app的广泛应用,安全问题成为人们最关注的话题之一。移动app安全除了和软件开发密不可分之外,软件测试的作用也是不容忽视的。移动app安全测试是指测试人员利用各种测试手段验证Ap…...

原生微信小程序引入npm和安装Vant Weapp

目录一、引入npm安装Vant Weapp1、引入npm2、安装Vant Weapp3、修改 app.json4、修改 project.config.json二、构建npm一、引入npm安装Vant Weapp 环境:Windows10 开发工具:微信开发者工具 本地环境:已安装过node.js 1、引入npm cmd进入到你…...

ChatGPT文章自动发布WordPress

WordPress可以用ChatGPT发文章吗?答案是肯定的,ChatGPT官方有提供api接口,多以目前有很多的SEO工具具有自动文章生成自动发布的功能,使用SEO工具,我们可以通过疑问词和关键词进行文章生成,并定时发布到我们…...

vue项目使用watch监听器监听数据变化

vue项目使用watch监听器监听数据变化 1.概述 在开发项目中,有些场景是当用户点击某个按钮后改变某个属性的值,这个值改变时需要触发事件做一些事情。属性值什么时候改变是没法提前判断的,因此需要有个监听的角色,当监听到值改变…...

动态规划(背包问题)

动态规划 文章目录动态规划一、背包问题一、01背包二、完全背包问题三、多重背包问题四、分组背包问题一、背包问题 一、01背包 有 N 件物品和一个容量是 V 的背包。每件物品只能使用一次。 第 i 件物品的体积是 vi,价值是 wi。 求解将哪些物品装入背包&#xf…...

04741自考计算机网络原理最详细汇总

04741自考计算机网络原理知识点总结 引言 第一章 计算机网络概述 1.计算机网络基本概念与网络结构 1.1 计算机网络的概念; 1.2 计算机网络结构 1.3 数据交换技术 1.4 计算机网络性能 1.5 计算机网络体系结构 1.6 计算机网络与因特网发展简史 第二章 网络应用 2.1 网络应用体系…...

MySQL 入门学习笔记(二) 基本操作

MySQL 入门学习笔记(二) 数据库和表的基本操作 我们把一些表的集合称之为数据库,一个服务器中可以存在多个数据库.每个数据库中包含多个表,每个表都有一个名字作为标识,数据表则包含带有数据的记录. PS:SQL 语句对大小写不敏感. 操作数据库命令 在 MySQL 命令中,数据库用DAT…...

【Linux】理解文件系统

文章目录理解文件系统了解磁盘结构inode理解文件系统 了解磁盘结构 磁盘是计算机中的一个 机械设备 这个磁盘的盘片就像光盘一样,数据就在盘片上放着, 但是光盘是只读的,磁盘是可读可写的 机械硬盘的寻址的工作方式: 盘片不断旋转,磁头不断摆动,定位到特定的位置 我们可以把…...

Java如何String字符串带括号转成List

问题现象 今天在做一个需求:将存入数据库中的数据读到后解析成list遍历分析 数据格式: "[1677660600000, 1677660900000, 1677661200000]" "[5, 4, 4,3,2,0,0]" 我一开始想到的就是使用逗号分割即可 结果变成了这样的…...

react 使用 mqtt

也许很多人都好奇这个mqtt是什么东西,其实在互联网上可能不会使用到它,它是物联网上的东西,也是一种通信协议跟websocket。但它也能在浏览器跟服务器上跑,它的底层实现也是封装了websocket。 MQTT MQTT是一个客户端服务端架构的发…...

W25Q256被写保护如何修改

W25Q256被写保护如何修改1、 W25Q256数据读不到1.1 打印的寄存器的值1.2 可能原因1.3 解决办法1.4 用到的函数1、 W25Q256数据读不到 能够正确的读到ID,但是读到的数据不正确 1.1 打印的寄存器的值 0x2 BUSY :只读, 指令正在执行 WEL (1) &…...

论文投稿指南——中文核心期刊推荐(中国文学作品)

【前言】 🚀 想发论文怎么办?手把手教你论文如何投稿!那么,首先要搞懂投稿目标——论文期刊 🎄 在期刊论文的分布中,存在一种普遍现象:即对于某一特定的学科或专业来说,少数期刊所含…...

MySQL 问题总结

什么是MVCC? 说说MySQL实现MVCC的原理? MVCC,全称Multi-Version Concurrency Control,即多版本并发控制。MVCC是一种并发控制的方法,一般在数据库管理系统中,实现对数据库的并发访问。 对于「读已提交」和…...

62. 不同路径

62. 不同路径 一个机器人位于一个 m∗nm * nm∗n 网格的左上角 (起始点在下图中标记为 “Start” )。 机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Finish” )。 问总共有多少条不同的路…...

在windows安装python3.11同时进行一个数据的练习

安装包百度网盘如下: 链接:https://pan.baidu.com/s/1l9H1GWP64LOxLaXXLie2uA?pwd6666 提取码:6666 1.我们选择自定义安装 2.当我们点了自定义安装后就直接next 3.修改路径,之后点击安装(install) 4.安装完成,进行…...

Java接口专题

基本介绍 接口给出一些没有实现的方法,封装到一起,到某个类使用时再根据具体情况把这些方法写出来。 注意:在jdk7之前,接口里所有的方法都是抽象方法。在jdk8之后接口中可以有静态方法,默认方法 interface 接口名{/…...

6招优化WordPress打开速度-让你的网站飞起来

为什么我们的WordPress网站比你的快? 我们的官网是使用WordPress框架搭建的,有没有发现我们的网站非常快,而你的WordPress网站比较慢呢?那是因为我们的网站经过了优化。 WordPress 很慢? 为什么很多人都会觉得 Word…...

春天到了,来一场 VoxEdit 创作大赛吧!

春天的气息扑面而来,这是让你尽情绽放创造力的最佳时机!我们将以「春天」为主题来一场 VoxEdit 大赛。在这里,你可以展示你的才华并赢得 $SAND 奖励! 无论你是专业的设计师,还是仅仅喜欢创造美丽的艺术,这场…...

SpringBoot-17-MyBatis动态SQL标签之常用标签

文章目录 1 代码1.1 实体User.java1.2 接口UserMapper.java1.3 映射UserMapper.xml1.3.1 标签if1.3.2 标签if和where1.3.3 标签choose和when和otherwise1.4 UserController.java2 常用动态SQL标签2.1 标签set2.1.1 UserMapper.java2.1.2 UserMapper.xml2.1.3 UserController.ja…...

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造,完美适配AGV和无人叉车。同时,集成以太网与语音合成技术,为各类高级系统(如MES、调度系统、库位管理、立库等)提供高效便捷的语音交互体验。 L…...

深度学习在微纳光子学中的应用

深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向: 逆向设计 通过神经网络快速预测微纳结构的光学响应,替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…...

19c补丁后oracle属主变化,导致不能识别磁盘组

补丁后服务器重启,数据库再次无法启动 ORA01017: invalid username/password; logon denied Oracle 19c 在打上 19.23 或以上补丁版本后,存在与用户组权限相关的问题。具体表现为,Oracle 实例的运行用户(oracle)和集…...

Vue记事本应用实现教程

文章目录 1. 项目介绍2. 开发环境准备3. 设计应用界面4. 创建Vue实例和数据模型5. 实现记事本功能5.1 添加新记事项5.2 删除记事项5.3 清空所有记事 6. 添加样式7. 功能扩展:显示创建时间8. 功能扩展:记事项搜索9. 完整代码10. Vue知识点解析10.1 数据绑…...

从WWDC看苹果产品发展的规律

WWDC 是苹果公司一年一度面向全球开发者的盛会,其主题演讲展现了苹果在产品设计、技术路线、用户体验和生态系统构建上的核心理念与演进脉络。我们借助 ChatGPT Deep Research 工具,对过去十年 WWDC 主题演讲内容进行了系统化分析,形成了这份…...

深入浅出:JavaScript 中的 `window.crypto.getRandomValues()` 方法

深入浅出:JavaScript 中的 window.crypto.getRandomValues() 方法 在现代 Web 开发中,随机数的生成看似简单,却隐藏着许多玄机。无论是生成密码、加密密钥,还是创建安全令牌,随机数的质量直接关系到系统的安全性。Jav…...

第25节 Node.js 断言测试

Node.js的assert模块主要用于编写程序的单元测试时使用,通过断言可以提早发现和排查出错误。 稳定性: 5 - 锁定 这个模块可用于应用的单元测试,通过 require(assert) 可以使用这个模块。 assert.fail(actual, expected, message, operator) 使用参数…...

MySQL 8.0 OCP 英文题库解析(十三)

Oracle 为庆祝 MySQL 30 周年,截止到 2025.07.31 之前。所有人均可以免费考取原价245美元的MySQL OCP 认证。 从今天开始,将英文题库免费公布出来,并进行解析,帮助大家在一个月之内轻松通过OCP认证。 本期公布试题111~120 试题1…...

【Oracle】分区表

个人主页:Guiat 归属专栏:Oracle 文章目录 1. 分区表基础概述1.1 分区表的概念与优势1.2 分区类型概览1.3 分区表的工作原理 2. 范围分区 (RANGE Partitioning)2.1 基础范围分区2.1.1 按日期范围分区2.1.2 按数值范围分区 2.2 间隔分区 (INTERVAL Partit…...