大话设计模式读书笔记——工厂方法模式


1. 前言

简单工厂模式读书笔记中,介绍了用简单工厂模式实现一个简易计算器功能,在本章,我们将介绍一种新的设计模式——工厂方法模式,去实现计算器功能


2. 概念

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

3. UML类图

在这里插入图片描述

4. 工厂方法模式实现

现在需要在原来的计算器增加一种新的工厂和两种新的运算类(以后可以扩展更多的高级运算,比如正余弦、正余切等),不要影响原有的代码和运作。

4.1 UML类图

在这里插入图片描述

4.2 两个运算类

public class Pow extends Operation{
	public double getResult(double numberA,double numberB){
		return Math.pow(numberA, numberB)
	}
}
public class Log extends Operation{
	public double getResult(double numberA,double numberB){
		return Math.log(numberB)/Math.log(numberA);
	}
}

4.3 工厂接口

public interface IFactory{
	public Operation createOperation();
}

4.4 基础运算工厂类

//基础运算工厂
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;
	}
}

4.5 高级运算工厂类

//高级运算工厂
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;
	}
}

4.6 运算工厂类

public class OperationFactory{
	public static Operation createOperate(String opera){
		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;
	}
}

OperationFactory类已经不存在运算子类实例化的代码了。也就是说,在这个代码里,全部是接口与具体工厂类,并不存在具体的实现,与原来的OperationFactory类对比,实例化的过程延迟到了工厂子类中

5. 商场收银软件升级

策略模式读书笔记中,介绍了用装饰模式去设计商场收银软件,观察下面红框的代码:
在这里插入图片描述
在这个CashContext类中,case5和6显得特别的复杂,因此,我们尝试用工厂方法模式去合并一部分代码。
思路如下:
如果有“先打折后满减类”存在,那它应该有三个初始化参数:折扣值、满减条件、满减返利值,那么打折类,其实就是满减返利值条件为0的情况,另外满减类,就相当于折扣参数为1的情况,因此,我们可以抽象成两个工厂:先打折再满减先满减再打折两个工厂类。
下面给出UML类图和对应的实现代码。

5.1 UML类图

在这里插入图片描述

5.2 IFactory接口

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

5.3 IFactory接口的两个类

IFactory接口的两个类分别是先打折再满减类先满减再打折类

//先打折再满减
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 CashReturnRebateFactoryimplements 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(cr1);	//满m返n装饰满m返n的算法
		return cr2;
	}
}

"有了上面的这些准备后,CashContext类就简单多了,它针对的是ISale 接口、IFactory接口编程,然后两个工厂类,对于各个打折满减算法 CashSuper、CashNormal、CashReturn、CashRebate等具体类一无所知。实现了松耦合的目的。

5.4 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(1d,300d,100d);
				break;
			case 5://先打8折,再满300100
				fs = new CashRebateReturnFactory(0.8d,300d,50d);
				break;
			case 6://先满300100,再打8折
				fs = new CashReturnRebateFactory(1d,0d,0d);
				break;
		}
		this.cs = fs.createSalesModel();
	}

	public double getResult(double price,int num){
		//根据收费策略的不同,获取计算结果
		return this.cs.acceptCash(price,num);
	}
}

6. 总结

  1. 工厂方法克服了简单工厂违背开放-封闭原则的缺点,又保持了封装对象创建过程的优点。
  2. 对于复杂的参数的构造对象,可以很好地对外层屏蔽代码的复杂性。
  3. 很好的解耦能力。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

头盔程序员

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值