策略模式(Strategy Pattern):
定义一系列的算法,把它们一个个封装起来,并且使他们可相互替换。本模式使得算法的变化可以独立于使用它的客户。(Define a family of algorithms,encapsulate each one and make them interchangeable.Strategy lets the algorithmvary independently from clients that use it.)
策略模式本质是:分离算法,选择实现
通俗来讲:_策略模式对应于解决某一个问题的一个算法族,允许用户从该算法族中任选一个算法解决某一问题,同时可以方便的更换算法或者增加新的算法。并且由客户端决定调用哪个算法。_
开发中常见的场景:
策略模式的优点:
策略模式体现了面向对象程序设计中非常重要的两个原则:
举例:我们就以Java中的TreeSet为例,TreeSet仅仅知道它只是接收一个Comparator这种接口类型,但是具体是哪种实现类,TreeSet并不关心,实现类在真正的传入TreeSet之前,TreeSet本身是不知道的,所以我们可以自己去实现Comparator接口,然后在实现类里面去封装好我们自己的规则(这里的规则你可以当做是算法),比如说我们要实现对一个集合的元素排序,但是到底是要升序排序还是降序排序,这个完全由我们来去控制,我们可以把这种变化的内容封装到自己的实现类中,真正运行的时候才知道具体的实现。比如:
下面用策略模式来实现一个简单的 加减乘除的功能:
第一步:定义抽象策略角色,通常情况下使用接口或者抽象类去实现
/**
* 为策略对象定义一个接口
*/
public interface Strategy {
//实现2个数可以计算
public int calc(int num1,int num2);
}
第二步:定义具体策略角色(在此只定义加 减两种具体的策略)
/**
* 定义加法策略
*/
public class AddStrategy implements Strategy {
@Override
public int calc(int num1, int num2) { //实现接口中的方法,完成两个数的和
return num1+num2;
}
}
/**
* 定义减法策略
*/
public class SubStrategy implements Strategy {
@Override
public int calc(int num1, int num2) { //实现接口中的方法,完成两个数的差
return num1-num2;
}
}
第三步:定义环境角色,负责和具体的策略类交互,内部持有一个策略类的引用,给客户端调用。
/**
* 环境角色:负责和具体的策略类交互
*/
public class Environment {
//持有对策略类的引用
private Strategy strategy;
//有参的构造方法,通过构造器来注入
public Environment(Strategy strategy) {
this.strategy = strategy;
}
public int calulate(int a,int b){
return strategy.calc(a,b);
}
}
第四步:测试
/**
* 测试类
*/
public class TestStrategy {
public static void main(String[] args) {
Environment e = new Environment(new AddStrategy());//传入具体的策略类
int result = e.calulate(5, 7);
System.out.println("a+b="+result);
Environment r = new Environment(new SubStrategy());
System.out.println("a-b="+r.calulate(9,3));
}
}
控制台打印效果如图:
再比如:去买衣服
可用if else来实现,弊端也很明显,如代码注释中解释,代码参考如下:
/**
* 实现起来比较容易,符合一般开发人员的思路
* 假如,类型特别多,算法比较复杂时,整个条件语句的代码就变得很长,难于维护。
* 如果有新增类型,就需要频繁的修改此处的代码!
* 不符合开闭原则!
*/
public class TestStrategy {
public double getPrice(String type, double price) {
if (type.equals("普通客户小批量")) {
System.out.println("不打折,原价");
return price;
} else if (type.equals("普通客户大批量")) {
System.out.println("打九折");
return price * 0.9;
} else if (type.equals("老客户小批量")) {
System.out.println("打八五折");
return price * 0.85;
} else if (type.equals("老客户大批量")) {
System.out.println("打八折");
return price * 0.8;
}
return price;
}
}
下面用策略模式来实现去买衣服打折的问题:
第一步:定义抽象策略角色,通常情况下使用接口或者抽象类去实现
public interface Strategy {
public double getPrice(double standardPrice);
}
第二步:定义具体策略角色
/**
* 新客户小批量
*/
public class NewCustomerFewStrategy implements Strategy {
@Override
public double getPrice(double standardPrice) {
System.out.println("不打折,原价");
return standardPrice;
}
}
/**
* 新客户大批量
*/
public class NewCustomerManyStrategy implements Strategy {
@Override
public double getPrice(double standardPrice) {
System.out.println("打九折");
return standardPrice*0.9;
}
}
/**
* 老客户小批量
*/
public class OldCustomerFewStrategy implements Strategy {
@Override
public double getPrice(double standardPrice) {
System.out.println("打八五折");
return standardPrice*0.85;
}
}
/**
* 老客户大批量
*/
public class OldCustomerManyStrategy implements Strategy {
@Override
public double getPrice(double standardPrice) {
System.out.println("打八折");
return standardPrice*0.8;
}
}
第三步:定义环境角色,负责和具体的策略类交互,内部持有一个策略类的引用,给客户端调用。
/**
* 负责和具体的策略类交互
* 这样的话,具体的算法和直接的客户端调用分离了,使得算法可以独立于客户端独立的变化。
* 如果使用spring的依赖注入功能,还可以通过配置文件,动态的注入不同策略对象,动态的切换不同的算法.
*/
public class Context {
private Strategy strategy; //当前采用的算法对象
//可以通过构造器来注入
public Context(Strategy strategy) {
super();
this.strategy = strategy;
}
//可以通过set方法来注入
public void setStrategy(Strategy strategy) {
this.strategy = strategy;
}
public void pringPrice(double s){
System.out.println("您该报价:"+strategy.getPrice(s));
}
}
第四步:测试
/**
* 测试类
*/
public class Client {
public static void main(String[] args) {
Strategy s1 = new OldCustomerManyStrategy();
Context ctx = new Context(s1);
ctx.pringPrice(500);
}
}
运行此类,控制台打印效果如图:
至此,策略模式的解释 和2个详细的案例介绍已完毕~
如果想了解更多设计模式,可点击:设计模式概述 以及 23种设计模式的介绍
如果觉得写的不错 或者想了解更多,欢迎收藏和关注~~
原网址: 访问
创建于: 2023-06-15 09:42:55
目录: default
标签: 无
未标明原创文章均为采集,版权归作者所有,转载无需和我联系,请注明原出处,南摩阿彌陀佛,知识,不只知道,要得到
java windows火焰图_mob64ca12ec8020的技术博客_51CTO博客 - 在windows下不可行,不知道作者是怎样搞的 监听SpringBoot 服务启动成功事件并打印信息_监听springboot启动完毕-CSDN博客 SpringBoot中就绪探针和存活探针_management.endpoint.health.probes.enabled-CSDN博客 u2u转换板 - 嘉立创EDA开源硬件平台 Spring Boot 项目的轻量级 HTTP 客户端 retrofit 框架,快来试试它!_Java精选-CSDN博客 手把手教你打造一套最牛的知识笔记管理系统! - 知乎 - 想法有重合-理论可参考 安宇雨 闲鱼 机械键盘 客制化 开贴记录 文本 linux 使用find命令查找包含某字符串的文件_beijihukk的博客-CSDN博客_find 查找字符串 ---- mac 也适用 安宇雨 打字音 记录集合 B站 bilibili 自行搭建 开坑 真正的客制化 安宇雨 黑苹果开坑 查找工具包maven pom 引用地 工具网站 Dantelis 介绍的玩轴入坑攻略 --- 关于轴的一些说法 --- 非官方 ---- 心得而已 --- 长期开坑更新 [本人问题][新开坑位]关于自动化测试的工具与平台应用 机械键盘 开团 网站记录 -- 能做一个收集的程序就好了 不过现在没时间 -- 信息大多是在群里发的 - 你要让垃圾佬 都去一个地方看难度也是很大的 精神支柱 [超级前台]sprinbboot maven superdesk-app 记录 [信息有用] [环境准备] [基本完成] [sebp/elk] 给已创建的Docker容器增加新的端口映射 - qq_30599553的博客 - CSDN博客 [正在研究] Elasticsearch, Logstash, Kibana (ELK) Docker image documentation elasticsearch centos 安装记录 及 启动手记 正式服务器 39 elasticsearch 问题合集 不断更新 6.1.1 | 6.5.1 两个版本 博客程序 - 测试 - bug记录 等等问题 laravel的启动过程解析 - lpfuture - 博客园 OAuth2 Server PHP 用 Laravel 搭建带 OAuth2 验证的 RESTful 服务 | Laravel China 社区 - 高品质的 Laravel 和 PHP 开发者社区 利用Laravel 搭建oauth2 API接口 附 Unauthenticated 解决办法 - 煮茶的博客 - SegmentFault 思否 使用 OAuth2-Server-php 搭建 OAuth2 Server - 午时的海 - 博客园 基于PHP构建OAuth 2.0 服务端 认证平台 - Endv - 博客园 Laravel 的 Artisan 命令行工具 Laravel 的文件系统和云存储功能集成 浅谈Chromium中的设计模式--终--Observer模式 浅谈Chromium中的设计模式--二--pre/post和Delegate模式 浅谈Chromium中的设计模式--一--Chromium中模块分层和进程模型 DeepMind 4 Hacking Yourself README.md update 20211011
Laravel China 简书 知乎 博客园 CSDN博客 开源中国 Go Further Ryan是菜鸟 | LNMP技术栈笔记 云栖社区-阿里云 Netflix技术博客 Techie Delight Linkedin技术博客 Dropbox技术博客 Facebook技术博客 淘宝中间件团队 美团技术博客 360技术博客 古巷博客 - 一个专注于分享的不正常博客 软件测试知识传播 - 测试窝 有赞技术团队 阮一峰 语雀 静觅丨崔庆才的个人博客 软件测试从业者综合能力提升 - isTester IBM Java 开发 使用开放 Java 生态系统开发现代应用程序 pengdai 一个强大的博主 HTML5资源教程 | 分享HTML5开发资源和开发教程 蘑菇博客 - 专注于技术分享的博客平台 个人博客-leapMie 流星007 CSDN博客 - 舍其小伙伴 稀土掘金 Go 技术论坛 | Golang / Go 语言中国知识社区
最新评论