策略模式--strategy

article/2025/8/22 20:32:07

策略模式

含义:

策略模式(Strategy)属于对象行为型设计模式,

1.主要是定义一系列的算法

2.把这些算法一个个封装成拥有共同接口的单独的类,并且使它们之间可以互换。

  • 策略模式使这些算法在客户端调用它们的时候能够互不影响地变化。这里的算法不要狭义的理解为数据结构中算法,可以理解为不同的业务处理方法

策略模式由三个角色组成:

在这里插入图片描述

策略模式使用场景:

同一个系统中存在不同的逻辑算法,而彼此之间在不同场景中需要实现动态替换,

  • 支付方式
    可以选择:支付宝,微信,银联等,彼此之间就可以相互替换,
  • 打折促销活动
    有双11活动,双12活动,会员活动,彼此之间可以相互替换

案例 :排序问题

1. int[ ]数组

Sorter1

public class Sorter1 {public void sort(int[] arr) {for(int i=0; i<arr.length - 1; i++) {int minPos = i;for(int j=i+1; j<arr.length; j++) {minPos = arr[minPos]> arr[j] ? j  : minPos;}swap(arr, i, minPos);}}//sort(int)void swap(int[] arr, int i, int j) {int temp = arr[i];arr[i] = arr[j];arr[j] = temp;}}

测试:

    @Testpublic void test01() {int[] a = {9, 2, 3, 5, 7, 1, 4};Sorter1 sorter = new Sorter1();sorter.sort(a);System.out.println(Arrays.toString(a));}

在这里插入图片描述

2. Cat[ ]数组

Comparable接口https://blog.csdn.net/weixin_48052161/article/details/115414069

在这里插入图片描述

Cat

public class Cat implements Comparable<Cat> {Integer weight, height;public Cat(int weight, int height) {this.weight = weight;this.height = height;}@Overridepublic int compareTo(Cat c) {if(this.weight < c.weight) return -1;else if(this.weight > c.weight) return 1;else return 0;}@Overridepublic String toString() {return "Cat{" +"weight=" + weight +", height=" + height +'}';}
}

Sorter2

public class Sorter2 {public void sort(Cat[] arr) {for (int i = 0; i < arr.length - 1; i++) {int minPos = i;for (int j = i + 1; j < arr.length; j++) {minPos = arr[minPos].compareTo(arr[j]) == 1 ? j : minPos;}swap(arr, i, minPos);}}void swap(Cat[] arr, int i, int j) {Cat temp = arr[i];arr[i] = arr[j];arr[j] = temp;}}

测试:

@Testpublic void test02() {Cat[] a= new Cat[]{new Cat(3,3),new Cat(5,5),new Cat(1,1)};Sorter2 sorter = new Sorter2();sorter.sort(a);System.out.println(Arrays.toString(a));}

在这里插入图片描述

3. 策略模式 定制规则

comparator 定制排序

在这里插入图片描述

Sorter3

public class Sorter3<T> {public void sort(T[] arr, Comparator<T> comparator) {for (int i = 0; i < arr.length - 1; i++) {int minPos = i;for (int j = i + 1; j < arr.length; j++) {minPos = comparator.compare(arr[minPos],arr[j])==1 ? j : minPos;}swap(arr, i, minPos);}}void swap(T[] arr, int i, int j) {T temp = arr[i];arr[i] = arr[j];arr[j] = temp;}}

测试 ; cat比较 按体重降升序,如果体重相同身高降序排列

  //按体重降升序,如果体重相同身高降序@Testpublic void test03() {Cat[] a= new Cat[]{new Cat(1,3),new Cat(3,3),new Cat(1,1),new Cat(1,2)};Sorter3<Cat> sorter = new Sorter3();sorter.sort(a,(o1,o2)->{if(o1.weight<o2.weight){return -1;}else if(o1.weight>o2.weight){return 1;}else{//Integer默认重写的compareTo方法,模式是从小到大排序return -o1.height.compareTo(o2.height);}});System.out.println(Arrays.toString(a));}

在这里插入图片描述

Integer 实现了Comparable接口 ,且重写了compareTo方法,模式是从小到大排序

在这里插入图片描述
在这里插入图片描述

4.JDK源码中策略模式排序

Arrays.sort()在这里插入图片描述

  • 在JDK中,我们调用数组工具类Arrays的一个排序方法sort时,可以使用默认的排序规则(升序),也可以自定义指定排序的规则,也就是可以自定义实现升序排序还是降序排序,方法的源码如下:
 @Testpublic void test04() {Cat[] a= new Cat[]{new Cat(1,3),new Cat(3,3),new Cat(1,1),new Cat(1,2)};Arrays.sort(a,(o1,o2)->{if(o1.weight<o2.weight){return -1;}else if(o1.weight>o2.weight){return 1;}else{//Integer默认重写的compareTo方法,模式是从小到大排序return -o1.height.compareTo(o2.height);}});System.out.println(Arrays.toString(a));}

案例:支付问题

1、创建一个策略接口

PayStrategry

public interface PayStrategry {boolean pay(int money);//支付BigDecimal queryBalance(String accountNo);//查询余额
}

2、接下来定义2个实现类示例

AliPayStrategy


public class AliPayStrategy implements PayStrategry{@Overridepublic boolean pay(int money) {System.out.println("支付宝支付成功");return true;}@Overridepublic BigDecimal queryBalance(String accountNo) {System.out.println("支付宝余额10元");return new BigDecimal(10);}}

WechatPayStrategy


public class WechatPayStrategy implements PayStrategry{@Overridepublic boolean pay(int money) {System.out.println("微信支付成功");return true;}@Overridepublic BigDecimal queryBalance(String accountNo) {System.out.println("微信余额10元");return new BigDecimal(10);}}

3.一般方法测试

public class TestPayStrategy {public static void main(String[] args) {String pay = "aliPay";PayStrategy payStrategy = null;if(pay.equals("aliPay")){payStrategy = new AliPayStrategy();}else if(pay.equals("wechatPay")){payStrategy = new WechatPayStrategy();}payStrategy.pay(10);payStrategy.queryBalance("XXX");}
}

通过枚举类的实现方式来改造一下测试方法:

PayEnum

public enum PayEnum {AliPay("aliPay",new AliPayStrategy()),WechatPay("wechatPay",new WechatPayStrategy());private String key;private PayStrategry value;PayEnum(String key, PayStrategry value) {this.key = key;this.value = value;}public static PayStrategry getValue(String key){for (PayEnum payEnum : PayEnum.values()){if (payEnum.key.equals(key)){return payEnum.value;}}return new AliPayStrategy();//没有合适key则默认阿里支付}}

测试一下

public class TestPayStrategy {public static void main(String[] args) {String pay = "aliPay";PayStrategry payStrategy = PayEnum.getValue(pay);payStrategy.pay(10);payStrategy.queryBalance("XXX");}

在这里插入图片描述

现在增加一种支付方式,icbc支付

  • 只需要对枚举类代码进行修改

PayEnum

public enum PayEnum {AliPay("aliPay",new AliPayStrategy()),WechatPay("wechatPay",new WechatPayStrategy()),ICBCPay("icbc", new PayStrategry() {@Overridepublic boolean pay(int money) {System.out.println("icbc支付成功");return true;}@Overridepublic BigDecimal queryBalance(String accountNo) {System.out.println("icbc余额10元");return new BigDecimal(10);}});private String key;private PayStrategry value;PayEnum(String key, PayStrategry value) {this.key = key;this.value = value;}public static PayStrategry getValue(String key){for (PayEnum payEnum : PayEnum.values()){if (payEnum.key.equals(key)){return payEnum.value;}}return new AliPayStrategy();//没有合适key则默认阿里支付}}

测试一下

public class TestPayStrategy {public static void main(String[] args) {String pay = "aliPay";PayStrategry payStrategy = PayEnum.getValue(pay);payStrategy.pay(10);payStrategy.queryBalance("XXX");System.out.println("----------------------------");PayStrategry payStrategy1 = PayEnum.getValue("icbc");payStrategy1.pay(10);payStrategy1.queryBalance("XXX");}}

在这里插入图片描述

这么改写之后,如果以后新增了其他支付方式只需要再枚举类中新怎过一种枚举类型并且实现自定义支付逻辑之后,其他代码就无需变更

在这里插入图片描述

策略模式总结

优点

  • 结构清晰明了、使用简单直观;
  • 耦合度相对而言较低,扩展方便;
  • 操作封装也更为彻底,数据更为安全;

缺点

  • 策略类数量会增多,每个策略都是一个类,复用的可能性很小,增加维护难度
  • 所有的策略类都需要对外暴露

应用场景

  1. 如果在一个系统里面有许多类,它们之间的区别仅在于它们的行为,那么使用策略模式可以动态地让一个对象在许多行为中选择一种行为。多个类只有算法或行为上稍有不同的场景
  2. 一个系统需要动态地在几种算法中选择一种。算法需要自由切换的场景
  3. 如果一个对象有很多的行为,如果不用恰当的模式,这些行为就只好使用多重的条件选择语句来实现。
  4. 需要屏蔽算法规则的场景

注意事项

  • 如果一个系统的策略多于四个,就需要考虑使用混合模式,解决策略类膨胀的问题

http://chatgpt.dhexx.cn/article/x0U2wvIM.shtml

相关文章

策略模式(Strategy)

设计模式系列 Strategy 策略模式——对象行为模式 1.意图 定义一系列的算法&#xff0c;把它们一个个封装起来&#xff0c;并且使它们可相互替换。本模式使得算法可独立使用它的客户而变化。 2.适用性 当存在以下情况时使用Strategy模式 许多相关的类仅仅是行为有异。“策…

CTA 策略分享之三 -- 策略优化

上一个帖子介绍了一个趋势跟踪策略的优化思路&#xff0c;今天我们继续对策略进行分析&#xff0c;找到另外的优化方法。先看回测的权益曲线&#xff1a; 看到在2017 8月份到2018 2月份策略出现了较大的回撤。先定性分析一下&#xff0c;应该是在这段时间内日线级别的图形上震…

证书扩展中的oid

4.1.2.9. 扩展 该字段必须仅在版本为 3 时出现&#xff08;第 4.1.2.1 节&#xff09;。 如果存在&#xff0c;该字段是一个或多个证书扩展的序列。 Internet PKI 中证书扩展的格式和内容在第 4.2 节中定义。 为 X.509 v3 证书定义的扩展提供了将附加属性与用户或公钥相关联以及…

OID科普:物联网OID与互联网域名的区别 | 圣笛数控

1.主导机构不同&#xff0c;物联网OID是以全球共同参与的国际标准组织统一分配。各国管理自己境内部分&#xff0c;各国之间又可以互通。安全机制比互联网域名更高&#xff0c;既有高度自治又有全球互通。中国是整个体系中最大的支持者和应用者。 2.表现形式不同&#xff0c;物…

OID技术与物联网、区块链、大数据的关系 | OID科普

一、什么是物联网&#xff1f; 物联网既是网络与物品与企业与人与万物互联&#xff0c;更是信息技术业务和应用。是利用局部网络或互联网等通信技术把传感器、控制器、机器、人员和物等通过新的方式联在一起&#xff0c;形成人与物、物与物相联&#xff0c;实现信息化、远程管…

ArcGIS中ObjectID,FID和OID字段区别

ArcGIS中ObjectID&#xff0c;FID和OID字段区别 当我们创建一个Shapefiles&#xff08;shp&#xff09;, geodatabase feature classes&#xff08;gdb中的要素类&#xff09;或独立的dBase表&#xff08;dbf&#xff09;时&#xff0c;ArcGIS会自动为上述三种格式创建一个ID字…

圣笛数控|OID是什么?看OID在未来人类社会生活中的地位

OID定义&#xff0c;OID是什么&#xff1f; OID&#xff08;Object Identifier 对象标识符&#xff09;&#xff0c;是由国际三大标准组织ISO、IEC、ITU向全球颁布并供各国共同遵守的物品身份标识标准体系&#xff0c;现已被208个国家和地区采用。OID作为全球新物联通识标准&a…

OID科普:OID为什么被称为元标识?

物联网的标识有很多种&#xff0c;包括应用标识、载体标识以及网络标识&#xff0c;我们常见的 IC 卡、二维码、RFID 及传感器都可归为载体标识。当需要用到不同体系下的标识符时&#xff0c;如何处理不同标识符之间的兼容性等问题呢&#xff1f;这个时候&#xff0c;三大国际组…

SIFT+RANSAC做图像矫正

做图像矫正时使用了一下sift算法&#xff0c;尽管sift确实很牛&#xff0c;但还是会出现一些误匹配&#xff0c;直接计算两张影像的单应矩阵会出现很大误差&#xff0c;因此可以在计算时使用RANSAC算法在单应矩 阵的约束下剔除误匹配&#xff0c;并计算单应矩阵&#xff0c;基…

opencv沿斜线切割图片

opencv沿斜线切割图片 opencv如果沿水平或者数值的线来切割图片&#xff0c;是很简单的。但是&#xff0c;如果沿着斜线&#xff0c;那么就不能直接进行切割了。 我的思路是&#xff0c;根据直线上两点来确定直线方程&#xff0c;然后&#xff0c;逐个遍历图像中元素&#xf…

mean shift 图像分割(三)

Reference: [1] Mean shift: A robust approach toward feature space analysis, PAMI, 2002 [2] mean shift,非常好的ppt &#xff0c;百度文库链接 [3] Pattern Recognition and Machine Learning, Bishop, 2006&#xff0c;Sec 2.5 [4] Computer Vision Algorithms and App…

mean shift 图像分割(一、二、三)

MeanShift图像分割算法&#xff1a;大概是将复杂的背景&#xff0c;通过粗化提取整体信息&#xff0c;进而将图像分割。 接下来我想&#xff0c;将会抽出一部分时间&#xff0c;研究一下这个算法&#xff0c;以最终实现手势形状提取。 《Mean Shift: A Robust Approach Towar…

OpenCV在图像上画正弦曲线(c++)

写在前面&#xff1a;欢迎来到「湫歌」的博客。我是秋秋&#xff0c;一名普通的在校大学生。在学习之余&#xff0c;用博客来记录我学习过程中的点点滴滴&#xff0c;也希望我的博客能够更给同样热爱学习热爱技术的你们带来收获&#xff01;希望大家多多关照&#xff0c;我们一…

基于mean shift的图像分割

1 mean shift算法 Mean Shift 这个概念最早是由Fukunaga 等人[1]于1975 年在一篇关于概率密度梯度函数的估计中提出来的,其最初含义正如其名,就是偏移的均值向量,在这里Mean Shift 是一个名词,它指代的是一个向量,但随着Mean Shift 理论的发展,Mean Shift 的含义也发生了变化,如…

OpenCV对图像进行切边

1、概述 案例&#xff1a;使用OpenCV对旋转图片及正常图片进行切边。 A&#xff1a;对正常图片切边的步骤 1.加载图像 2.对图像进行灰度化 3.边缘检测 4.轮廓发现 5.找出符合目标的最大外接矩形&#xff0c;并使用矩形的四个坐标点绘制线 6.根据找到Rect在原图上切除ROI区域 7.…

双曲正割matlab求解

&#xff0c;取N305&#xff0c;且x在区间内按照5等分取值。 matlab中对于双曲正割函数可以直接用sech求解&#xff0c;自己编代码的过程永远无法逃避&#xff0c;&#xff0c;因为这个有现成的&#xff0c;那个可能没有&#xff0c;遇到棘手复杂的任务&#xff0c;全靠现成调包…

MATLAB:图像裁切(imcrop函数)

对图像进行裁切可用imcrop函数&#xff0c;实现过程如下&#xff1a; close all; %关闭当前所有图形窗口&#xff0c;清空工作空间变量&#xff0c;清除工作空间所有变量 clear all; clc; [A,map]imread(peppers.png); %读入图像 rect[75 68 130 112]; …

matlab关于图像切割的一些总结:imcrop,getrect,ndgrid,函数

之前查看这么多人写的博客&#xff0c;乱七八糟的&#xff0c;说法不一还有些有错误&#xff0c;误导人。现在记下来&#xff0c;希望给后来人一点指引。 1.imcrop函数 这个函数是 imcrop的第一二元素代表左上角的横纵坐标&#xff0c;第三四元素代表矩行框的宽高 pic imre…

代码实现数学图形之常用函数,幂,对数,指数,正弦,余弦,正切,余切,反正弦,反余弦,反正切,反余切,双曲正弦,双曲余弦,双曲正切,双曲余切,正割函数,余割函数,双曲正割,双曲正割.

(1)幂函数 X的N次幂. 按 CtrlC 复制代码 按 CtrlC 复制代码 脚本代码中X,N都为变量,两个变量会生成一个二维数据,得到一个平面图形.pow_sign是一个保留正负号的pow函数,其C实现为: static float yf_pow_sign(float a, float b) {float s yf_sign(a);a ::fabsf(a);if (…