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

news2024/9/24 11:23:07

工厂模式

  • 简单工厂实现
  • 工厂模式实现
  • 简单工厂 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返n
    public 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.8
    public 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=100
    public 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://300100
                fs = new CashRebateReturnFactory(1,300d,100d);
                break;
            case 5://先打8,再满300100
                fs = 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("**********************************************");
	}
}

工厂方法模式总结

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

工厂方法模式的好处

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

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

CMMI流程规范—实现与测试

一、概述实现与测试(Implementation and Test, IT)的目的是依据系统设计文档,编写并测试整个系统的代码。在本规范中,实现与测试是“编程、代码审查、单元测试、集成测试、缺陷管理与改错”的综合表述。实现与测试过程域是SPP模型…

从 AI 绘画到 ChatGPT,聊聊生成式 AI

我们小时候经常有幻想,未来不用再去上班了,在工厂工作的都是机器人。在家也不用打扫卫生,机器人可以包揽一切。不知不觉间,我们小时候的幻想已经慢慢变成现实,工厂里有了多种型号的机械臂,代替了部分流水线…

Vue3中watch的value问题

目录前言一,ref和reactive的简单复习1.ref函数1.2 reactive函数1.3 用ref定义对象类型数据不用reactive二,watch的value问题2.1 ref2.1.1 普通类型数据2.1.2 对象类型数据2.1.3 另一种方式2.2 reactive三,总结后记前言 在Vue3中,…

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

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

微信小程序通过 node 连接 mysql——方法,简要原理,及一些常见问题

前言 博主自己在22年夏天根据课程要求做了一个小程序连接阿里云服务器的案例,在最近又碰到了相应的需求。 原参考文章:微信小程序 Node连接本地MYSQL_微信小程序nodejs连接数据库_JJJenny0607的博客-CSDN博客 ,还请多多支持原作者! 第二次…

vue2 @hook 的解析与妙用

目录前言几种用法用法一 将放在多个生命周期的逻辑,统一到一个生命周期中用法二 监听子组件生命周期运行的情况运用场景场景一 许多时候,我们不得不在不同的生命周期中执行某些逻辑,并且这些逻辑会用到一些通用的变量,这些通用变量…

nginx日志服务之敏感信息脱敏

1. 创建实验资源 开始实验之前,您需要先创建实验相关资源。 日志服务之敏感信息脱敏与审计 2. 创建原始数据 本步骤将指导您如何创建NGINX模拟数据。 双击打开虚拟桌面的Firefox ESR浏览器。 在RAM用户登录框中单击下一步,并复制粘贴页面左上角的子…

使用groovy代码方式解开gradle配置文件神秘面纱

来到这里的是不是都有以下疑问: 1.build.gradle配置文件结构好复杂啊,怎么记? 2.内部是怎么进行分析和执行的? 3.为什么可以在配置文件里面写groovy代码,怎么识别的? 4.怎么才能很方便的记住和快速上手…

空口协议Eapol、802.11 Action、802.11 BAR 和 802.11BA、802.11 Encrypted Data讲解

如下报文 可以看到,除了有之前开放认证的报文之外,还多了 EAPOL 次握手的报文。另外,还有其他几种类型的报文:802.11 Action、802.11 BAR 和 802.11BA、802.11 Encrypted Data ​ 密匙认证协议EAPOL: EAP是Extensible Authentication Protocol的缩写,EAPOL就是(EAP…

Python搭建一个steam钓鱼网站,只要免费领游戏,一钓一个准

前言 嗨喽~大家好呀,这里是魔王呐 ❤ ~! 我们日常上网的时候,总是会碰到一些盗号的网站,或者是别人发一些链接给你, 里面的内容是一些可以免费购物网站的优惠券、游戏官网上可以免费领取皮肤、打折的游戏。 这些盗号网站统一的目…

go版本分布式锁redsync使用教程

redsync使用教程前言redsync结构Pool结构Mutex结构acquire加锁操作release解锁操作redsync包的使用前言 在编程语言中锁可以理解为一个变量,该变量在同一时刻只能有一个线程拥有,以便保护共享数据在同一时刻只有一个线程去操作。对于高可用的分布式锁应…

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

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

【C语言进阶:指针的进阶】函数指针

本章重点内容: 字符指针指针数组数组指针数组传参和指针传参函数指针函数指针数组指向函数指针数组的指针回调函数指针和数组面试题的解析⚡函数指针 函数指针:指向函数的指针。 通过之前的学习我们知道数组指针中存放的是数组的地址,那么函…

如何在网络安全中使用人工智能并避免受困于此

人工智能在网络安全中的应用正在迅速增长,并对威胁检测、事件响应、欺诈检测和漏洞管理产生了重大影响。根据Juniper Research的一份报告,预计到2023年,使用人工智能进行欺诈检测和预防将为企业每年节省110亿美元。但是,如何将人工…

Sqoop 使用详解

Sqoop 概述Sqoop 是Apache 旗下的一款开源工具,用于Hadoop与关系型数据库之间传送数据,其核心功能有两个:导入数据和导出数据。导入数据是指将MySQL、Oracle等关系型数据库导入Hadoop的HDFS、Hive、HBase等数据存储系统;导出数据是…

web学习-Node.js入门学习

web学习-Node.js入门学习1.回顾与思考2. 初识Node.js2.1 Node.js的简介2.2Node.js的环境安装2.3. fs文件系统模块2.3.1 fs.readFile()2.3.2 fs.writeFile()2.3.3 练习-整理考试成绩2.3.4 fs模块-路径动态拼接的问题2.4 path路径模块2.5 http模块2.5.1 服务器相关的概念2.5.2 创…

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

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

Java之注解

注解1.1 注解的概念1.2 内置注解1.3 元注解1.4 自定义注解1.1 注解的概念 Annotation 是从JDK5.0 开始引入的新技术 Annotation的作用: 不是程序本身,可以对程序做出解释(这一点和注释comment没什么区别)可以被其他程序&#xff…

解读场景化视频制作工具的实现过程

内容视频化正当其时,企业级智创工具创造新价值。全领域的内容视频化已是显性之势,其不仅覆盖传媒行业,更多泛行业正在以视频化内容的多元姿态创造新的商业价值。于是,不仅新闻传媒行业在超前体验智能化视频创造的效能红利&#xf…

ClickHouse进阶篇-多表连接物化视图

简介 在写这篇文章的时候doris 1.2 的物化视图只是支持单表建立物化视图,现在说下ClickHouse多表的物化视图。 前言 本文翻译自 Altinity 针对 ClickHouse 的系列技术文章。面向联机分析处理(OLAP)的开源分析引擎 ClickHouse,因…