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

策略模式(Strategy Pattern)

编写鸭子项目,具体要求如下:
1) 有各种鸭子(比如 野鸭、北京鸭,水鸭等,鸭子有各种行为,比如 叫,飞行等)
2)显示鸭子的信息
传统方案解决鸭子问题
1) 传统的设计方法(类图)

 

2) 代码实现
创建一个 maven 项目 strategy
在项目路径下创建抽象父类 cn.baisee.strategy.Duck
public abstract class Duck {
/**
* 显示鸭子的信息
*/
public abstract void display();
/**
* 鸭子行为
*/
public void fly() {
System.out.println("鸭子会飞");
}
/**
* 鸭子行为
*/
public void quack() {
System.out.println("鸭子会叫");
}
}
创建野鸭子子类 cn.xs.strategy.WildDuck
public class WildDuck extends Duck {
/**
* 显示鸭子信息
*/
public void display() {
System.out.println(" 这是野鸭子 ");
}
}
创建北京鸭子类 cn.xs.strategy.PekingDuck
public class PekingDuck extends Duck {
/**
* 显示鸭子信息
*/
public void display() {
System.out.println(" 这是北京鸭 ");
}
/**
* 因为北京鸭不能飞翔,所以需要重写 fly
*/
@Override
public void fly() {
System.out.println("北京鸭不能飞翔");
}
}
创建玩具鸭子类 cn.xs.strategy.ToyDuck
public class ToyDuck extends Duck {
/**
* 显示鸭子信息
*/
public void display() {
System.out.println(" 这是玩具鸭 ");
}
/**
* 因为玩具鸭不能飞翔,所以需要重写 fly
*/
@Override
public void fly() {
System.out.println("玩具鸭不能飞翔");
}
/**
* 因为玩具鸭不能叫,所以需要重写 quack
*/
@Override
public void quack() {
System.out.println("玩具鸭不能叫");
}
}
分析传统方案:
1)其它鸭子,都继承了 Duck 类,所以 fly 让所有子类都会飞了,这是不正确的
2)上面说的 1 的问题,其实是继承带来的问题:对类的局部改动,尤其超类的局部改动,会影响其他
部分,会有溢出效应
3)为了改进 1 问题,我们可以通过覆盖 fly 方法来解决 => 覆盖解决
4)问题又来了,如果我们有一个玩具鸭子 ToyDuck ,这样就需要 ToyDuck 去覆盖 Duck 的所有实现的
方法 => 策略模式
基本介绍
1)策略模式(Strategy Pattern)中,定义算法族,分别封装起来,让他们之间可以互相替换,此模式
让算法的变化独立于使用算法的客户
2)这算法体现了几个设计原则,第一、把变化的代码从不变的代码中分离出来;第二、针对接口编程而
不是具体类(定义了策略接口);第三、所用组合/聚合,少用继承(客户通过组合方式使用策略)
策略模式解决鸭子问题:
分析:分别定义封装行为接口,实现算法族,超类里放行为接口对象,在子类里具体设定飞行对象。原
则就是:分离变化部分,封装接口,基于接口编程各种功能,此模式让行为的变化独立于算法的使用者
针对飞行这个行为,我们定义策略接口 cn.xs.strategy.FlyBehavior
public interface FlyBehavior {
/**
* 抽象的飞行方法
*/
void fly();
}
定义三种飞行行为实现飞行策略接口
第一个,飞行能力很好的行为 cn.xs.strategy.GoodFlyBehavior
public class GoodFlyBehavior implements FlyBehavior {
/**
* 实现飞行方法
*/
public void fly() {
System.out.println("飞翔技术高超");
}
}
第二个,飞行能力不好的行为 cn.xs.strategy.BadFlyBehavior
public class BadFlyBehavior implements FlyBehavior {
/**
* 实现飞行方法
*/
public void fly() {
System.out.println("飞翔能力一般");
}
}
第三个,没有飞行能力 cn.xs.strategy.NoFlyBehavior
public class NoFlyBehavior implements FlyBehavior {
/**
* 实现飞行方法
*/
public void fly() {
System.out.println("没有飞行能力");
}
}
将策略接口聚合进 Duck
public abstract class Duck {
/* 聚合飞翔行为策略接口 */
protected FlyBehavior flyBehavior;
/**
* 显示鸭子的信息
*/
public abstract void display();
/**
* 鸭子行为
*/
public void fly() {
if (flyBehavior != null) {
flyBehavior.fly();
}
}
/**
* 鸭子行为
*/
public void quack() {
System.out.println("鸭子会叫");
}
}
Duck 子类中将 FlyBeHavior 初始化
野鸭子:
/**
* 初始化飞行行为
*/
public WildDuck() {
flyBehavior = new GoodFlyBehavior();
}
北京鸭:
/**
* 初始化飞行行为
*/
public PekingDuck() {
flyBehavior = new NoFlyBehavior();
}
玩具鸭:
/**
* 初始化飞行行为
*/
public ToyDuck() {
flyBehavior = new NoFlyBehavior();
}
去掉所有子类中重写的 fly 方法
新建cn.xs.strategy.Client 测试类进行测试:
public class Client {
/**
* 测试方法
*
* @param args
*/
public static void main(String[] args) {
System.out.println("======野鸭子======");
WildDuck wildDuck = new WildDuck();
wildDuck.fly();
System.out.println("======北京鸭======");
PekingDuck pekingDuck = new PekingDuck();
pekingDuck.fly();
System.out.println("======玩具鸭======");
ToyDuck toyDuck = new ToyDuck();
toyDuck.fly();
}
}
运行 main 方法:

 

 

策略模式在 jdk 中的使用:
1jdk Arrays Comparator 就使用了策略模式
2)代码演示:
Integer[] arr = {1,5,3,7,8};
Arrays.sort(arr, new Comparator<Integer>() {
public int compare(Integer o1, Integer o2) {
return o1 - o2;
}
});
函数式接口 Comparator 就是一个策略接口,compare 就是一个排序的行为,
我们可以自己定义不同的 实现,来对数组进行各种排序,不同的排序规则就是不同的行为,就跟鸭子的飞行能力一样
策略模式的注意事项和细节:
1)策略模式的关键是:分析项目中变化部分与不变部分
2)策略模式的核心思想:多用组合/聚合 少用继承;用行为类组合,而不是行为的继承。更具弹性
3)体现了 "对修改关闭,对扩展开放" 原则,客户端增加行为不用修改原有代码,只要添加一种策略(或者行为)即可,避免了使用多重转移语句(if...else if...else
4)提供了可以替换继承关系的方法:策略模式将算法封装在独立的 Strategy 类中使得你可以独立于其 Context 改变它,使它易于切换、易于理解、易于扩展
5)需要注意的是:每添加一个策略就要增加一个类,当策略过多是会导致类数目庞大

相关文章:

策略模式(Strategy Pattern)

编写鸭子项目&#xff0c;具体要求如下&#xff1a; 1&#xff09; 有各种鸭子&#xff08;比如 野鸭、北京鸭&#xff0c;水鸭等&#xff0c;鸭子有各种行为&#xff0c;比如 叫&#xff0c;飞行等&#xff09; 2&#xff09;显示鸭子的信息 传统方案解决鸭子问题 1&#xff0…...

《Qt6开发及实例》6-2 Qt6基础图形的绘制

目录 一、绘图框架设计 二、绘图区的实现 2.1 PaintArea类 2.2 PaintArea类讲解 三、主窗口的实现 3.1 MainWidget类 3.2 MainWidget类讲解 3.3 槽函数编写 3.5 其他内容 一、绘图框架设计 界面 两个类 ​ 二、绘图区的实现 2.1 PaintArea类 ​paintarea.h #ifndef…...

LeetCode 382. 链表随机节点

原题链接 难度&#xff1a;middle\color{orange}{middle}middle 题目描述 给你一个单链表&#xff0c;随机选择链表的一个节点&#xff0c;并返回相应的节点值。每个节点 被选中的概率一样 。 实现 SolutionSolutionSolution 类&#xff1a; Solution(ListNodehead)Solution…...

iOS开发AppleDeveloper中给别人授权开发者权限后,对方一直显示不了我的开发账号team

在iOS开发经常出现多人协作开发的情况。这时我们通常要发邮件邀请别的用户为开发者或者app管理就可以开发我们自己的项目了。但是这次我给别人授权开发者权限后&#xff0c;发现别人权限中没有证书相关权限如图&#xff1a;并且别人登录该账号后&#xff0c;在xcode中只有一个看…...

FreeRTOS数据类型和编程规范

目录 数据类型 变量名 函数名 宏的名 数据类型 每个移植的版本都含有自己的portmacro.h头文件&#xff0c;里面定义了2个数据类型 TickType_t FreeRTOS配置了一个周期性的时钟中断&#xff1a;Tick Interrupt每发生一次中断&#xff0c;中断次数累加&#xff0c;这被称为t…...

【python知识】win10下如何用python将网页转成pdf文件

一、说明 本篇记录一个自己享用的简单工具。在大量阅读网上文章中&#xff0c;常常遇到一个专题对应多篇文章&#xff0c;用浏览器的收藏根本不够。能否见到一篇文章具有搜藏价值&#xff0c;就转到线下&#xff0c;以备日后慢慢消化吸收。这里终于找到一个办法&#xff0c;将在…...

C语言常见关键字

写在前面 这个博客是结合C语言深度解剖这本书和我以前学的知识综合而成的,我希望可以更见详细的谈一下C语言的关键字,内容有点多,有错误还请斧正. 常见关键字 下面我们说下C语言的关键字,所谓的关键字是指具有特定功能的单词,我们可以使用关键字来帮助我们完成不同的事物.C语…...

【MT7628】固件开发-SDK4320添加MT7612E WiFi驱动操作说明

解压5G WiFi MT7612E驱动1.1解压指令 tar -xvf MT76x2E_MT7620_LinuxAP_V3.0.4.0_P2_DPA_20160308.tar.bz2 1.2解压之后会出现以下两个目录 rlt_wifi rlt_wifi_ap 1.3将解压后的文件拷贝到系统下 拷贝路径 RT288x_SDK/source/linux-2.6.36.x/drivers/net/wireless 内核中打开驱…...

如何从手工测试进阶自动化测试?阿里10年测开经验分享...

随着行业的竞争加剧&#xff0c;互联网产品迭代速度越来越快&#xff0c;QA 与测试工程师都需要在越来越短的测试周期内充分保证质量。可是&#xff0c;App 测试面临着很多挑战&#xff0c;比如多端发布、多版本发布、多机型发布等等&#xff0c;导致了手工测试很难完全胜任。因…...

C++复习笔记11

1. vector是表示可变大小数组的序列容器。 2. 就像数组一样&#xff0c;vector也采用的连续存储空间来存储元素。也就是意味着可以采用下标对vector的元素进行访问&#xff0c;和数组一样高效。但是又不像数组&#xff0c;它的大小是可以动态改变的&#xff0c;而且它的大小会被…...

【MT7628】固件开发-SDK4320添加MT7628 WiFi驱动操作说明

解压2.4G WiFi MT7628驱动1.1解压指令 tar -xvf MT7628_LinuxAP_V4.1.0.0_DPA_20160310.tar.bz2 1.2解压之后会出现以下两个目录 mt_wifi mt_wifi_ap 1.3将解压后的文件拷贝到系统下 拷贝路径 RT288x_SDK/source/linux-2.6.36.x/drivers/net/wireless 内核中打开驱动编译修改R…...

C#开发的OpenRA游戏加载界面的实现

C#开发的OpenRA游戏加载界面的实现 游戏的UI是一个游戏必备, 但是游戏的UI都是自己处理的,不能使用像Windows自带的UI。 这样游戏的UI,其实也是使用游戏的方式来显示的, 只不过使用了低帧率的方式来显示。 比如OpenRA游戏界面,就会显示如下: 游戏的界面有很多,先从一个简…...

渲染农场优势是什么_云渲染农场怎么用?

在回答渲染农场的优势这个问题之前&#xff0c;我先申明一下本文中提到的渲染农场/云渲染平台/云渲染农场&#xff0c;都特指CG领域内的专业3D渲染平台&#xff0c;有一些文章会强调这个叫法的区别&#xff0c;但是业内一般都不会分这么细&#xff0c;所以也就不赘述了。渲染农…...

SoapUI、Jmeter、Postman三种接口测试工具的比较分析

目录 前言 1. 用例组织方式 2. 支持的接口类型与测试类型 3. 配置不同接口类型 4. 自定义变量以及变量的作用域 5. 数据源、生成器&#xff0c;进行参数化 6. 流程控制 7. 结果解析、展示 8. 断言 9. 脚本扩展能力 10. 团队协作 总结 重点&#xff1a;配…...

Python内置函数 — sort,sorted

1、sort 列表的属性方法&#xff0c;对列表进行排序&#xff0c;默认升序&#xff0c;返回None值。 源码注释&#xff1a; """ Sort the list in ascending order and return None.The sort is in-place (i.e. the list itself is modified) and stable (i.e.…...

mysql事务隔离级别

mysql锁机制及原理1.隔离级别2.实践2.1查看事务隔离级别2.2 设置隔离级别2.3 不可重复读2.4 幻读3.幻读怎么解决3.1 Record Lock3.2 Gap Lock3.3 Next-Key Lock引用&#xff1a;https://blog.csdn.net/xinyuan_java/article/details/1284932051.隔离级别 SERIALIZABLE(序列化)…...

【C++】string类(下)

文章目录1.迭代器(正向遍历)begin有两个版本2.反向迭代器(反向遍历)rbegin由两个版本3. at4. insert ——头插在pos位置前插入一个字符串在pos位置前插入n个字符在迭代器前插入一个字符5. erase从pos位置开始删除len个字符从迭代器位置开始删除6. replace——替换从pos位置开始…...

Elasticsearch: Prefix queries - 前缀查询

Prefix queries 被用于在查询时返回在提供的字段中包含特定前缀的文档。有时我们可能想使用前缀查询单词&#xff0c;例如 Leonardo 的 Leo 或 Marlon Brando、Mark Hamill 或 Martin Balsam 的 Mar。 Elasticsearch 提供了一个前缀查询&#xff0c;用于获取匹配单词开头部分&a…...

GEE学习笔记 七十七:GEE学习方法简介

这是一篇关于学习方法的思考探索&#xff0c;当然我不会大篇文章介绍什么学习方法&#xff08;因为我也不是这方面的专家?&#xff09;&#xff0c;这个只是总结一下我是如何学习GEE以及在学习中遇到问题时如何解决问题的。我写这篇文章的目的就是在和一些学习GEE的新同学接触…...

20基于主从博弈的智能小区代理商定价策略及电动汽车充电管理MATLAB程序

参考文档&#xff1a;《基于主从博弈的智能小区代理商定价策略及电动汽车充电管理》基本复现仿真平台&#xff1a;MATLABCPLEX/gurobi平台优势&#xff1a;代码具有一定的深度和创新性&#xff0c;注释清晰&#xff0c;非烂大街的代码&#xff0c;非常精品&#xff01;主要内容…...

镜像里切换为普通用户

如果你登录远程虚拟机默认就是 root 用户&#xff0c;但你不希望用 root 权限运行 ns-3&#xff08;这是对的&#xff0c;ns3 工具会拒绝 root&#xff09;&#xff0c;你可以按以下方法创建一个 非 root 用户账号 并切换到它运行 ns-3。 一次性解决方案&#xff1a;创建非 roo…...

鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个医院查看报告小程序

一、开发环境准备 ​​工具安装​​&#xff1a; 下载安装DevEco Studio 4.0&#xff08;支持HarmonyOS 5&#xff09;配置HarmonyOS SDK 5.0确保Node.js版本≥14 ​​项目初始化​​&#xff1a; ohpm init harmony/hospital-report-app 二、核心功能模块实现 1. 报告列表…...

【Java学习笔记】BigInteger 和 BigDecimal 类

BigInteger 和 BigDecimal 类 二者共有的常见方法 方法功能add加subtract减multiply乘divide除 注意点&#xff1a;传参类型必须是类对象 一、BigInteger 1. 作用&#xff1a;适合保存比较大的整型数 2. 使用说明 创建BigInteger对象 传入字符串 3. 代码示例 import j…...

Golang——9、反射和文件操作

反射和文件操作 1、反射1.1、reflect.TypeOf()获取任意值的类型对象1.2、reflect.ValueOf()1.3、结构体反射 2、文件操作2.1、os.Open()打开文件2.2、方式一&#xff1a;使用Read()读取文件2.3、方式二&#xff1a;bufio读取文件2.4、方式三&#xff1a;os.ReadFile读取2.5、写…...

Ubuntu系统多网卡多相机IP设置方法

目录 1、硬件情况 2、如何设置网卡和相机IP 2.1 万兆网卡连接交换机&#xff0c;交换机再连相机 2.1.1 网卡设置 2.1.2 相机设置 2.3 万兆网卡直连相机 1、硬件情况 2个网卡n个相机 电脑系统信息&#xff0c;系统版本&#xff1a;Ubuntu22.04.5 LTS&#xff1b;内核版本…...

高考志愿填报管理系统---开发介绍

高考志愿填报管理系统是一款专为教育机构、学校和教师设计的学生信息管理和志愿填报辅助平台。系统基于Django框架开发&#xff0c;采用现代化的Web技术&#xff0c;为教育工作者提供高效、安全、便捷的学生管理解决方案。 ## &#x1f4cb; 系统概述 ### &#x1f3af; 系统定…...

sshd代码修改banner

sshd服务连接之后会收到字符串&#xff1a; SSH-2.0-OpenSSH_9.5 容易被hacker识别此服务为sshd服务。 是否可以通过修改此banner达到让人无法识别此服务的目的呢&#xff1f; 不能。因为这是写的SSH的协议中的。 也就是协议规定了banner必须这么写。 SSH- 开头&#xff0c…...

echarts使用graphic强行给图增加一个边框(边框根据自己的图形大小设置)- 适用于无法使用dom的样式

pdf-lib https://blog.csdn.net/Shi_haoliu/article/details/148157624?spm1001.2014.3001.5501 为了完成在pdf中导出echarts图&#xff0c;如果边框加在dom上面&#xff0c;pdf-lib导出svg的时候并不会导出边框&#xff0c;所以只能在echarts图上面加边框 grid的边框是在图里…...

python读取SQLite表个并生成pdf文件

代码用于创建含50列的SQLite数据库并插入500行随机浮点数据&#xff0c;随后读取数据&#xff0c;通过ReportLab生成横向PDF表格&#xff0c;包含格式化&#xff08;两位小数&#xff09;及表头、网格线等美观样式。 # 导入所需库 import sqlite3 # 用于操作…...

AT模式下的全局锁冲突如何解决?

一、全局锁冲突解决方案 1. 业务层重试机制&#xff08;推荐方案&#xff09; Service public class OrderService {GlobalTransactionalRetryable(maxAttempts 3, backoff Backoff(delay 100))public void createOrder(OrderDTO order) {// 库存扣减&#xff08;自动加全…...