1.工厂方法模式(Factory Method)定义

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

1.1 UML图:

主要有4个对象:

  • 抽象工厂(Abstract Creator):提供一个创建产品的接口。调用者可以通过它访问具体工厂的工厂方法。
  • 具体工厂(Concrete Creator):继承自抽象工厂,并实现其创建对象的方法。
  • 抽象产品(Product):定义了产品的规范,描述了产品的主要特性和功能。
  • 具体产品(Concrete Product):实现了抽象产品中所定义的接口,由具体工厂来创建,与同具体工厂之间是一一对应的。
    在这里插入图片描述

2.工厂方法模式举例:

业务场景:需要实现一个商场收银系统,有四种策略,

  1. 正常结账
  2. 打折
  3. 满减
  4. 先打折再满减
    简单工厂模式 -> 工厂方法模式:

简单工厂模式UML图:简单工厂 + 策略模式 + 装饰模式 具体实现逻辑,见装饰模式 -> 2.装饰模式举例:
在这里插入图片描述
工厂方法模式UML:策略模式 + 装饰模式 + 工厂方法模式
在这里插入图片描述

2.2 核心代码:

ISale接口

public interface ISale {public double acceptCash(double price,int num);}

IFactory接口

public interface IFactory {public ISale createSalesModel(); //创建销售模式}

CashContex:

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);}
}

CashRebateReturnFactory

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;         //将包装好的算法组合返回}
}

CashReturnRebateFactory

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;         //将包装好的算法组合返回}
}

CashSuper

public class CashSuper implements ISale {protected ISale component;//装饰对象public void decorate(ISale component) {this.component=component;}public double acceptCash(double price,int num){double result = 0d;if (this.component != null){//若装饰对象存在,则执行装饰的算法运算result = this.component.acceptCash(price,num);    }return result;}
}

CashReturn

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);   }}

CashRebate

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);}}

CashNormal

public class CashNormal implements ISale {//正常收费,原价返回public double acceptCash(double price,int num){return price * num; }    
}

DemoTest

public class Demotest {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("**********************************************");}
}

输出结果:
在这里插入图片描述

3. 工厂方法模式的优缺点;

  • 优点:
    • 可以避免创建者和具体产品之间的紧密耦合,针对工厂接口编程,而并非具体实现类。
    • 单一职责原则。可以将产品创建代码放在程序的单一位置,从而使得代码更容易维护。
    • 开闭原则。无需更改现有客户端代码,就可以在程序中引入新的产品类型。
  • 缺点:
    • 每增加一个产品就要增加一个具体产品类和一个对应的具体工厂类,增加了系统的复杂度。

4. 总结

  • 通常我们把被创建的对象称之为【产品】, 创建【产品】的对象称为【工厂】。
  • 当产品比较固定且数量少的情况下,只需要一个工厂类就可以,称之为【简单工厂】, 多个工厂时,就称为工厂方法模式,其中工厂方法使一个类的实例化延迟到其子类,而简单工厂实例化就是在唯一工厂类

5.参考

  • https://www.cnblogs.com/mklblog/p/18029716

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/web/93600.shtml
繁体地址,请注明出处:http://hk.pswp.cn/web/93600.shtml
英文地址,请注明出处:http://en.pswp.cn/web/93600.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

冒泡排序——简单理解和使用

阅前声明:如果想直接了解冒泡排序的简化思想,请跳至文章尾部在介绍之前,我们先看一个用到该功能的实战训练(本人也是从中开始认识到冒泡排序这个函数定义)对于小白来说,我的思路如下:1.题目中涉…

AI应用商业化加速落地 2025智能体爆发与端侧创新成增长引擎

今年以来,人工智能 (AI) 正在进入从算力投入到云服务消耗再到商业化收入,最终回到算力再投入的良性循环,而 AI 应用的起量正是推动这一飞轮效应的关键。7 月 31 日,国务院常务会议审议通过了《关于深入实施 “人工智能 ” 行动的意…

Pytest测试框架基础及进阶

Pytest测试框架基础# Pytest测试框架介绍# Pytest是Python一款三方测试框架,用于编写和运行单元测试、集成测试和功能测试。Pytest测试框架具有简单、灵活、易于扩展等特点,被广泛应用于Python项目的测试工作中。 Pytest主要特点: 简单易用…

航空装备先进加工工艺与制造技术论坛——2025成都航空装备展

300参展企业 11500㎡展区面积 7大专业展区 12000观众规模15同期会议 160发言嘉宾 5000参会嘉宾 100媒体报道航空工业飞速发展,先进加工工艺与制造技术成为了支撑航空装备性能提升、质量保障和产能优化的核心基石。为探索前沿技术路径、凝聚行业创新力量,…

为什么品牌更愿意为新品打广告?

品牌资源向新品广告倾斜,可以说是市场上的普遍现象。尤其对于没有明星产品的品牌而言,新品推广时企业的重要曝光节点。下面就让我们一同来了解下,为什么品牌更愿意为新品打广告。一、市场需求更充分新品广告往往承担着市场教育的功能&#xf…

电子电气架构 --- 关于整车信息安全的一些思考

我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 做到欲望极简,了解自己的真实欲望,不受外在潮流的影响,不盲从,不跟风。把自己的精力全部用在自己。一是去掉多余,凡事找规律,基础是诚信;二是…

报错:Eplan无法打开数据库的解决方法

详细报错信息:无法打开数据库 E:\eplan\部件\Microsoft\ESS_part001.mdb。针对64位版本的EPLAN 平台需要使用64位版本的Microsoft Office. 一、报错及解决方法 报错信息:无法打开数据库 E:\eplan\部件\Microsoft\ESS_part001.mdb。针对64位版本的EPLAN 平…

深度学习篇---卷积核的权重

卷积核权重:在深度学习的卷积操作中,“卷积核的权重” 是最核心的概念之一,它决定了卷积核能从图像中 “看到” 什么特征(比如边缘、纹理,甚至是眼睛、车轮这样的复杂结构)。我们可以把它理解成卷积核的 “…

SMTPman,smtp ssl助力安全高效邮件传输!

SMTPman,smtp ssl助力安全高效邮件传输!SMTPman,smtp ssl不仅仅是一种邮件协议方式,更是企业日常运营的重要支撑。通过SMTPman,smtp ssl,用户可以获得更快的投递速度,更稳定的连接,以…

学习日志37 python

1 Python 和 Java 在类属性(静态属性)和实例属性的处理题目执行以下程序,输出结果为() class Base(object):count 0def __init__(self):pass b1 Base() b2 Base() b1.count b1.count 1 print(b1.count,end" …

对于QPS的理解和简单

QPS(Queries Per Second) 是衡量系统吞吐量的核心指标,表示每秒能处理的请求数量。以下是关于QPS的完整解析和实践指南:一、QPS的核心公式 QPS 总请求量 / 请求总时间(秒)典型场景计算: 日请求…

【笔记ing】考试脑科学 脑科学中的高效记忆法

前言本书是拙作《高中生学习法》的修订版。《高中生学习法》出版已有十余年。这期间,脑科学研究不断进步,十几年前无法解释的事情现在已经开始逐渐明晰。同时,书中有些内容甚至已经被明确证实是错误的。也就是说,《高中生学习法》…

Web安全 - 构建安全可靠的API:基于国密SM2/SM3的文件上传方案深度解析

文章目录概述1. 缘起:挑战与目标2 . 核心架构:非对称签名与摘要算法的珠联璧合威胁模型(我们要防的攻击)密钥管理体系3 . 签名与验证:一步一解,安全闭环3.1 A系统:签名的生成(请求前…

【MyBatis-Plus】一、快速入门

这里写自定义目录标题MyBatis-Plus 概述快速入门入门案例常用注解常见配置MyBatis-Plus 概述 MyBatis-Plus 简介: MyBatis-Plus 是在 MyBatis 基础上开发的一个 增强工具包,它简化了 MyBatis 的开发,减少了大量重复代码。它保持了 MyBatis …

PostgreSQL导入mimic4

一、PostgreSQL连接验证 正确连接命令 使用psql工具连接目标数据库,格式为:psql -h 127.0.0.1 -U 用户名 -d 数据库名 --password 示例(用户名Shinelon,数据库mimic):psql -h 127.0.0.1 -U Shinelon -d mi…

css中 hsl() 的用法

好的 👍 我来详细介绍一下 CSS hsl() 的用法。1. 基本语法 color: hsl(hue, saturation, lightness);hue(色相) 取值范围:0 ~ 360(角度值,代表色环的角度)0 或 360 → 红色120 → 绿色240 → 蓝…

企业级Spring事务管理:从单体应用到微服务分布式事务完整方案

企业级Spring事务管理:从单体应用到微服务分布式事务完整方案 🌟 你好,我是 励志成为糕手 ! 🌌 在代码的宇宙中,我是那个追逐优雅与性能的星际旅人。 ✨ 每一行代码都是我种下的星光,在逻辑的土…

继续记录面试题

坐在工位,没事干心慌的不行,可能也是房贷压的。一闲下来就开始胡思乱想,无法沉下心去背那些八股文。这才刚刚接到离职通知第三天啊。而且、我还在坐班呢!!! 哎、怪不得有句老话说的,人穷志短&a…

从零开始学习:深度学习(基础入门版)(第2天)

(一)在pycharm软件中,用python语言,opencv库实现以下功能(1.1)图片的边界填充核心流程:读取原始图像使用 cv2.imread() 加载名为 yueshan.png 的图像文件统一边界参数设定四周留白尺寸均为 50px(上下左右各…

HTTP协议-3-HTTP/2是如何维持长连接的?

先说结论:HTTP/2的“长连接” 一个TCP连接 多路复用 二进制帧 流控制 持久会话管理 它不只是“连接不断”,更关键的是:在这个长连接上,可以同时并发传输成百上千个请求和响应,互不阻塞! 1、HTTP/2的“…