简单理解常用设计模式(二)策略模式

设计模式C++实现(2)——策略模式 软件领域中的设计模式为开发人员提供了一种使用专家设计经验的有效途径。设计模式中运用了面向对象编程语言的重要特性:封装、继承、多态,真正领悟设计模式的精髓是可能一个漫长的过程,需要大量实践经验的积累。最近看设计模式的书,对于每个模式,用C++写了个小例子,加深一下理解。主要参考《大 阅读详情

写完简单工厂模式后,这里说说策略模式,厉害的观众已经发现了,简单工厂在有些场景非常不合适,例如市场营销的场景,商场打八折,打五折,满五百减一百,满两百减五十,不打折等。市场经常会变动这些策略,如果是简单工厂就需要每次都改动工厂类,用来添加新的策略,然后添加具体的实现类。这样每次变动都要修改项目,二次开发工作量很大,非常的不理想。

所以仔细思考。

每加一个策略,都加一个类,这样做好吗,面向对象不是类越多越好,类的划分是为了封装,但分装的基础是抽象,相同属性和功能的对象的抽象集合才是类。

这样思考发现,每个策略都是可以归类的,比如折扣类,满减类,原价类。这些类可以继承自一个促销类(父类),然后给调用者提供一个中间类,用来获得具体的策略实例,并且提供返回计算结果的方法(此方法使用策略实例执行对应的计算)。

这样调用者只需要new中间类,提供策略(促销)方式,对应的数字参数即可,通过中间类获取结果。

这样修改策略时只需要传入不同参数即可,不再需要修改代码。(添加不同策略类型的当然要修改代码,但这种变动很少,第一次开发基本就能确定有多少策略类型)

原书UML如下:


原书案例如下:



看到这里,问题来了,假如笔者是二次开发的程序员,看到封装的方法只是返回中间类对象,并且传参内容还是不好记忆的对象,传参的逻辑也要自己编写,会开喷的。

所以这里笔者参考原书又结合了简单工厂模式,将逻辑放到工厂类(结合中间类),传参改为便于记忆的数字(当然也可以是便于理解的单词)

调用类如下:

package com.gcc.strategyModel;

public class TestCash {
	
	/**
	 * CashContext是策略模式和抽象工厂的组合
	 * CashContext的辅助方法完成向上转型后对象的方法调用,900为原价
	 */
	public static void main(String[] args) throws Exception {
		
		CashContext cash1 = new CashContext(1);
		double result1 = cash1.getResult(900);
		System.out.println("原价为:"+result1);
		
		CashContext cash2 = new CashContext(2);
		double result2 = cash2.getResult(900);
		System.out.println("折后为:"+result2);
		
		CashContext cash3 = new CashContext(3);
		double result3 = cash3.getResult(900);
		System.out.println("满减后为:"+result3);
		
	}
	
}

工厂和策略结合的类如下:

package com.gcc.strategyModel;

import java.util.Properties;

/**
 *工厂模式和策略模式化结合 
 *
 */
public class CashContext {

	private CashSuper cs=null;

	public CashContext() {
		super();
	}

	/**
	 * 抽象工厂
	 * @param condition
	 * @throws ClassNotFoundException 
	 */
	public CashContext(int condition) throws Exception {
		//规定字典1为正常,2为折扣,3为返利,通过配置文件获得数据
		Properties prop = new Properties();
		prop.load(CashContext.class.getResourceAsStream("cash.properties"));
		double conditionNum = Double.parseDouble(prop.getProperty("conditionNum"));
		double rebateNum = Double.parseDouble(prop.getProperty("rebateNum"));
		double discountNum = Double.parseDouble(prop.getProperty("discountNum"));

		switch (condition) {
		case 1:
			cs= new CashNormal();
			break;
		case 2:
			cs=(CashSuper) CashDiscount.class//另一种反射的写法
				.getConstructor(double.class)
				.newInstance(discountNum);
			break;
		case 3:
			cs=(CashSuper) Class
				.forName(prop.getProperty("rebate"))
				.getConstructor(double.class,double.class)
				.newInstance(conditionNum,rebateNum);
			break;
		default:
			break;
		}
	}
	
	public double getResult(double money){
		return cs.acceptCash(money);
	}
	
}

这里笔者有其它的想法,因为编写代码时突然想到java反射,配合配置文件能进一步优化代码,这里举例了两种反射方式,第一种是通过类名.class然后获得构造方法再执行实例化,第二种是通过Class.forName(),参数为需要实例化的类的全路径,然后获得构造方法再执行实例化。

笔者支持前者,原因是:这样做不仅更加简单,而且更安全,它会在编译期间得到检查(后者不会)。由于它取消了对方法调用的需要,所以执行的效率也会更高。

至于参数数据,这里通过读取配置文件的方式来获得,方便修改。

另外值得注意的是这里的获取结果方法,灵活运用了java的多态,使得一个方法有多种实现方式。

配置文件cash.properties如下:

normal=com.gcc.strategyModel.CashNormal
conditionNum=500
rebateNum=100
discountNum=0.9
rebate=com.gcc.strategyModel.CashRebate
discount=com.gcc.strategyModel.CashDiscount

促销(策略)父类以及子类如下:

package com.gcc.strategyModel;

public interface CashSuper {
	
	/**
	 * 实际消费现金接口方法
	 * @param money
	 * @return
	 */
	public double acceptCash(double money);
	
}
package com.gcc.strategyModel;

public class CashDiscount implements CashSuper {

	private double discount;//折扣
	
	
	public CashDiscount() {
		super();
	}

	public CashDiscount(double discount){
		this.discount=discount;
	}
	
	@Override
	public double acceptCash(double money) {
		return money*(this.discount);
	}

}
package com.gcc.strategyModel;

public class CashNormal implements CashSuper {

	@Override
	public double acceptCash(double money) {
		return money;
	}

	
}
package com.gcc.strategyModel;

public class CashRebate implements CashSuper {

	private double rebate;//返利
	private double condition;//返利条件
	
	public CashRebate() {
		super();
	}

	public CashRebate(double condition,double rebate){
		this.rebate=rebate;
		this.condition=condition;
	}

	/**
	 * 例如消费800大于返利条件500,则返利100,返回实际消费额为800-100=700
	 */
	@Override
	public double acceptCash(double money) {
		if(money>=this.condition){
			money=money-rebate;
		}
		return money;
	}

	
}

到此完毕

no,no!

可能有人会提出,为什么中间类不用之前的简单工厂的方式,即如下方式:

package com.gcc.strategyModel;

import java.util.Properties;

/**
 *工厂模式和策略模式化结合 
 *
 */
public class CashContextTest {

	/**
	 * 工厂
	 * @param condition
	 * @throws ClassNotFoundException 
	 */
	public static CashSuper createCash(int condition) throws Exception {
		CashSuper cs=null;
		//规定字典1为正常,2为折扣,3为返利,通过配置文件获得数据
		Properties prop = new Properties();
		prop.load(CashContextTest.class.getResourceAsStream("cash.properties"));
		double conditionNum = Double.parseDouble(prop.getProperty("conditionNum"));
		double rebateNum = Double.parseDouble(prop.getProperty("rebateNum"));
		double discountNum = Double.parseDouble(prop.getProperty("discountNum"));

		switch (condition) {
		case 1:
			cs= new CashNormal();
			break;
		case 2:
			cs=(CashSuper) CashDiscount.class//另一种反射的写法
				.getConstructor(double.class)
				.newInstance(discountNum);
			break;
		case 3:
			cs=(CashSuper) Class
				.forName(prop.getProperty("rebate"))
				.getConstructor(double.class,double.class)
				.newInstance(conditionNum,rebateNum);
			break;
		default:
			break;
		}
		return cs;
	}
	
}

调用如下:

		CashSuper cash4 = CashContextTest.createCash(2);
		double result4=cash4.acceptCash(900);
		System.out.println("折后为:"+result4)

这样做在笔者看来是更加便于理解,但实际上这在使用时不知不觉耦合了底层逻辑代码。

调用者需要多知道底层接口CashSuper,不符合尽量解耦的原则。

策略模式的另外巧妙的一点就在于在中间类Context里添加了可以重用的方法如getResult(double money),进一步完成了解耦。

完毕,感谢你的观看





深入理解设计模式之策略模式 策略模式在 GoF 的《设计模式》一书中的定义为:定义一组算法类,将每个算法分别封装起来,让它们可以互相替换。策略模式使这些算法在客户端调用它们的时候能够互不影响地变化。简单来说,策略模式允许我们在运行时根据不同的情况选择不同的算法或行为,就如同在一场战斗中,战士可以根据敌人的特点和战场形势选择不同的武器和战术。 阅读详情

相关推荐

深入理解设计模式:策略模式的艺术与实践

在软件开发中,我们经常会遇到需要根据不同情况选择不同算法或行为的场景。传统的做法可能是使用大量的条件语句(if-else或switch-case),但随着需求的增加和变化,这种硬编码的方式会导致代码难以维护和扩展。策略模式(Strategy Pattern)正是为了解决这类问题而诞生的一种优雅的设计模式。 策略模式属于行为型设计模式,它定义了一系列算法,并将每个算法封装起来,使它们可以相互替换。这种模式让算法的变化独立于使用算法的客户端,从而实现了算法的灵活切换和扩展。

vvilkin的学习备忘 1366

设计模式-策略模式

总的说来策略模式: 优点: 1、 使用策略模式可以避免使用多重条件转移语句。多重转移语句不易维护。 2、 策略模式让你可以动态的改变对象的行为,动态修改策略 缺点: 1、客户端必须知道所有的策略类,并自行决定使用哪一个策略类。 2、类过多---策略模式造成很多的策略类,每个具体策略类都会产生一个新类。(这点可以通过享元模式来克服类过多) 实例代码:在C/S 的射击类游戏中,同一个角色,拿起不同的武器,会有不同的行为。武器可以随意的切换。 代码已上传GitHub,如需参考可自行下载: https:..

肥嘟嘟的左卫门 437

深入理解设计模式:《Head First设计模式》读书笔记 -- 策略模式

策略模式是23种设计模式中的一种,它被广泛应用于软件开发中以提供算法族的封装,并允许客户端在运行时选择算法的种类。策略模式定义了算法的家族,并让它们相互之间可以替换,且算法的变化不会影响到使用算法的客户端。在策略模式中,上下文通常是一个拥有策略接口引用的类,它通过策略接口实现具体策略的切换。上下文类的主要职责包括:维护一个策略对象的引用。提供设置策略对象的方法。根据需要调用策略对象的方法。上下文类通常会包含一组操作方法,这些方法会委派给当前激活的策略对象来执行具体的行为。

weixin_34945060的博客 995

设计模式之策略模式使用

设计模式之策略模式的使用

xiangwang2016的博客 617

告别手绘!用Aseprite+Unity Tilemap,从AI生成到2D游戏地图的保姆级搭建流程

本文详细介绍了如何利用Aseprite和Unity Tilemap从AI生成素材到搭建2D游戏地图的完整流程。涵盖AI生成素材的预处理、图层管理、动画制作,以及Unity中的Tilemap系统配置和性能优化技巧,帮助开发者高效创建像素风游戏地图。

weixin_29015483的博客 583

Allan方差读图分析IMU误差指标

Allan方差标定IMU参数实测分析

weixin_44927558的博客 3566

策略模式

一.小结 定义:定义一组算法,将每个算法都封装起来,并且使它们之间可以互换。 主要解决:在有多种算法相似的情况下,使用if…else所带来的复杂和难以维护。 优点:1.算法可以自由切换 2.避免使用多重条件判断 3.拓展性好 缺点:1.策略类会增多 2.所有策略类都需要对外暴露。 注意点:如果一个系统的策略多于四个,就需要考虑使用混合模式,解决策略类膨胀的问题。 通用UML图: 二.例子   在学习程序的时候,策略模式的"计算器"十分经典,列举如下: 抽离两数运算的算法 p

wangadping的博客 241

四、嘉立创EDA原理图绘制实战:从零搭建STM32温湿度监测系统

本文详细介绍了使用嘉立创EDA标准版从零开始绘制STM32温湿度监测系统原理图的完整流程。涵盖核心元器件选型、电源电路设计、ADC按键创新应用及模块化布局技巧,帮助电子爱好者快速掌握STM32系统设计,提升嵌入式开发实战能力。

h0i1j2k3l的博客 883

设计模式复习(十三)-------策略模式

1. 策略模式的简介 定义一系列算法,把它们一个个封装起来,并且使它们可互相替换。该模式使得算法可独立于使用它的客户而变化。 ——《设计模式》GoF 在软件构建过程中,某些对象使用的算法可能多种多样,经常改变,如果将这些算法都编码到对象中,将会使对象变得异常复杂;而且有时候支持不使用的算法也是一个性能负担。 如何在运行时根据需要透明地更改对象的算法?将算法与对象本身解耦,从而避免上述问题? 2. 策略模式的结构 环境(Context)角色:持有一个Strategy类的引用。 抽象策略(Strat

qq_41342326的博客 363

【CSP-J/S初赛知识点整理】

CSP-J/S初赛知识点整理

qq_43884946的博客 1万+

半导体功率器件IGBT工艺全流程

本文概述了功率器件IGBT(绝缘栅双极型晶体管)的关键制造流程。主要工艺包括:基板制备、离子注入(B+/P+/P+FS层)、绝缘膜形成与加工(CVD沉积及刻蚀)、沟槽刻蚀、电极形成(Emitter和Collector)等步骤。通过离子注入、化学气相沉积和物理气相沉积等半导体工艺,依次完成器件各功能层的构建,最终形成具备高功率特性的IGBT器件。该流程体现了功率半导体制造中典型的掺杂、薄膜沉积和图形化工艺技术。

750

一文搞懂策略模式(优化策略模式完全消除if else)

注重版权,转载请注明原作者和原文链接 作者:码农BookSea 原文链接:https://blog.youkuaiyun.com/bookssea/article/details/107309591 先看后赞,养成习惯。 点赞收藏,人生辉煌。 文章目录前言一、策略模式介绍二、策略模式应用(消除 if else)三、如何对策略模式进行优化总结 前言 策略模式是设计模式里面比较简单的设计模式,其特点简单又实用,是我最喜欢的模式之一。当初学策略模式是因为听说策略模式可以用来消除 if else语句。 多重条件语句.

BookSea的博客 3万+

保姆级教程:用MATLAB复现格拉斯哥大学FMCW雷达数据集多普勒谱(附完整代码与避坑指南)

本文提供了一份详细的MATLAB教程,指导如何复现格拉斯哥大学FMCW雷达数据集的多普勒谱分析。从环境准备、数据获取到距离压缩、MTI滤波、时频分析(STFT)以及结果后处理,涵盖了完整流程,并附有优化代码和避坑指南,特别适合雷达信号处理研究者和工程师。

weixin_28720767的博客 116

深入理解JavaScript设计模式之策略模式

本文我以幽默+实践的方式学习策略模式,通过计算年终奖,表单校验,柯里化策略模式方法校验深入学习总结策略模式,反复学,反复看!

前端开发工程师 1935

CATIA文件的网页预览方案

CATIA是工业设计中广泛使用的专业软件,产出`.CATPart`或 `.CATProduct`等文件类型,当资产数量较大时,我们希望快捷预览这些文件,就有了`CATPart`文件网页预览的需求 但我们知道,网页上无法直接渲染`CATPart`这种复杂的文件, CATIA生成的文件(如 `CATPart` 和 `CATProduct`)不仅包含三维几何信息(例如点、线和曲面),还涵盖了丰富的元数据与专业设计特征。 那有没有办法,能实现CATIA文件在网页上的便捷预览?

weixin_44211633的博客 1449

让 RAP 弹窗参数真正变成必填:Excel Upload Action 的两种实现路径

摘要 在RAP应用中,action弹窗参数经常缺乏必填校验,导致用户体验差。本文提出两种解决方案:1)在action实现中手动校验,简单但交互不流畅;2)通过root abstract entity和abstract BDEF建模,利用field(mandatory)实现框架级校验,推荐此长期方案。后者将约束集中到模型层,使UI与执行期校验一致,特别适合ABAP Cloud环境。以Excel导入为例,强制填写备注和明确选择试运行,可避免审计问题,提升系统可靠性。

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 198

深入理解设计模式-策略模式(结合简单工厂、反射、Spring详细讲解)

文章目录前言一、定义二、使用场景三、代码样例1.需求2.类图3.代码四、优缺点五、延伸样例1.结合简单工厂样例2.结合反射样例3.结合Spring样例结尾 前言 在现实生活中常常遇到实现某种目标存在多种策略可供选择的情况,例如,出行旅游可以乘坐飞机、乘坐火车、骑自行车或自己开私家车等,超市促销可以釆用打折、送商品、送积分等方法。 在软件开发中也常常遇到类似的情况,当实现某一个功能存在多种算法或者策略,我们可以根据环境或者条件的不同选择不同的算法或者策略来完成该功能,如数据排序策略有冒泡排序、选择排序、插入

少说,多做 1万+

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

【设计模式】策略模式 VS. 简单工厂

学习了设计模式的前两章,对简单工厂模式和策略模式做一下总结。 什么是简单工厂?     简单工厂是面向对象的过程,包括:封装、继承和多态。     第一步:封装,即抽象出超类;(现金收费抽象类)     第二步:继承,即子类继承超类;(继承“现金收费抽象类”得到“正常收费子类、打折收费子类、返利收费子类”)                   多态,体现在这些不同的子类中,如用同样的ac

张美红 1771

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

设计模式详解之策略模式

策略模式是一种应用广泛的行为型模式,核心思想是对算法进行封装,委派给不同对象来管理,本文将着眼于策略模式进行分享。

阿里技术 5815

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

设计模式: 对比简单工厂模式、策略模式和模板模式

代码看这篇:设计模式: 一个简单的策略模式demo 多个Pen接口的实现类 定义工厂类factory根据参数创建Pen实例 客户端通过factory创建的实例去调用具体方法 具体子类和钩子方法具体实现 客户端(Client) 模板方法比较好理解,就是通过抽象类定义模板,通过钩子方法来实现不同的行为。工厂模式和策略模式对比:工厂模式和策略模式区别以及使用

qq_41364834的博客 1846

设计模式-策略模式(Strategy)

策略模式是一种行为型设计模式,它定义了一系列算法或策略,并将每个算法封装在独立的类中,使得它们可以互相替换或独立于使用它的客户而变化。这种类型的设计模式属于行为型模式。当在处理一项业务时,如果有多种处理方式,并且需要再运行时决定使用哪一种具体实现,就会使用策略模式。策略模式的主要组成部分包括抽象策略(Strategy)类、具体策略(Concrete Strategy)类和环境(Context)类。抽象策略类是策略接口,定义了所有支持的算法;具体策略类是实现了抽象策略接口的类,表示每种具体的算法;

miaoyl的博客 5044

设计模式之策略模式

策略模式是一种面向对象设计模式,它允许在运行时选择算法的行为。这种模式使得可以定义一系列算法,并将每种算法封装起来,使它们可以相互替换,而不会影响到使用这些算法的客户端。策略模式的主要角色如下。我自己的理解:策略模式是在我们对一件事情实现的方法(策略),比如说要去西安旅行,去的方式有飞机、火车、大巴、自驾等。这些出行方式就是一个个不同的策略,可以根据自己的需求选择合适的策略。去的行为我们可以抽象成一个策略,然后去的方式是具体的策略,环境就是提供给我们选择的。

news_Q的博客 1744

设计模式--策略模式(由简单工厂到策略模式到两者结合图文详解+总结提升)

由简单工厂到策略模式到两者结合图文详解,重点在最后的总结提升,精彩不容错过

李赛男 1941

浅谈设计模式之简单工厂、策略模式

带你读懂几种常见的设计模式 第一弹 1、设计模式的六大原则 单一职责原则 每个类的职责尽量单一。这个在实际项目中很难做到。 开闭原则 对扩展开放,对修改关闭。这个原则还是很重要的。 里氏代换原则 只要父类能出现的地方子类就可以出现,而且替换为子类也不会产生任何错误或异常,使用者可能根本就不需要知道是父类还是子类。但是,反过来就不行了,有子类出现的地方,父类未必就能适应。这个原则挺不好理解的。 依赖倒转原则 针对接口编程,依赖于抽象而不依赖于具体。 接口隔离原.

学无止境! 496

23种设计模式之《策略模式(Strategy)》在c#中的应用及理解

策略模式通过将算法封装在独立的策略类中,使得算法的变化独立于使用它的客户端。客户端可以在运行时动态地选择不同的策略来执行任务,而不需要修改客户端代码。这种模式非常适合需要在运行时根据条件选择不同算法的场景。

yuanpan的专栏 1435
上一篇: 简单理解常用设计模式(一)简单工厂-附加UML解释
下一篇: 简单理解常用设计模式(三)常用设计原则
gcc_front
博客等级 码龄9年 16粉丝 98原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值