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

《设计模式》工厂方法模式

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.xdnf.cn/news/1317475.html

相关文章:

  • 【CV 目标检测】Fast RCNN模型②——算法流程
  • 代码随想录算法训练营四十四天|图论part02
  • 【Luogu】每日一题——Day21. P3556 [POI 2013] MOR-Tales of seafaring (图论)
  • 上网行为组网方案
  • 数据结构03(Java)--(递归行为和递归行为时间复杂度估算,master公式)
  • Mac(五)自定义鼠标滚轮方向 LinearMouse
  • Linux软件编程:进程与线程(线程)
  • JVM学习笔记-----StringTable
  • Docker Compose 安装 Neo4j 的详细步骤
  • PostgreSQL导入mimic4
  • go基础学习笔记
  • k8s集群搭建一主多从的jenkins集群
  • Win11 文件资源管理器预览窗格显示 XAML 文件内容教程
  • C++ vector的使用
  • 10 SQL进阶-SQL优化(8.15)
  • 说一下事件委托
  • Java 大视界 -- Java 大数据分布式计算在基因测序数据分析与精准医疗中的应用(400)
  • 【UEFI系列】ACPI
  • 跨越南北的养老对话:为培养“银发中国”人才注入新动能
  • JavaScript 性能优化实战:从评估到落地的全链路指南
  • Spark03-RDD02-常用的Action算子
  • 在鸿蒙中实现深色/浅色模式切换:从原理到可运行 Demo
  • E2B是一个开源基础设施,允许您在云中安全隔离的沙盒中运行AI生成的代码和e2b.dev网站
  • Diamond基础2:开发流程之LedDemo
  • c_str()函数的详细解析
  • 简单的 VSCode 设置
  • (nice!!!)(LeetCode 每日一题) 837. 新 21 点 (动态规划、数学)
  • bash shell 入门
  • 云智智慧停充一体云-allnew全新体验-路内停车源码+路外停车源码+充电桩源码解决方案
  • Rust:DLL 输出对象的生命周期管理