策略模式(Strategy)

2023-11-09

一.策略模式定义

定义一系列算法,把他们封装起来,并且他们可以相互替换。本模式使得算法可独立于使用他的客户而变化


二.策略模式结构说明

1.Strategy :策略接口,用来约束一系列具体的策略算法。Context使用这个接口来调用具体的策略实现定义的算法。

2.ConcreteStrategy:具体的策略实现,也就是具体的算法实现。

3.Context:上下文,负责和具体的策略类交互。通常上下文会持有一个真正的策略实现,上下文还可以让具体的策略类来获取上下文的数据,甚至可以让具体的策略类来回调上下文的方法。


三.策略模式的示例代码

package com.interfaces;

//策略接口
public interface Strategy {
	double arithmeticInterface();
}
package com.model;

import com.interfaces.Strategy;

//负责和策略接口交互的上下文类
public class Context {
	private Strategy strategy=null;
	

	public Context(Strategy strategy) {
		super();
		this.strategy = strategy;
	}

	public double  quote(){//能实现调用不同的算法
		return strategy.arithmeticInterface();
	}
	 
}
package com.model;

import com.interfaces.Strategy;

public class ConcreteStrategy implements Strategy {

	@Override
	public double arithmeticInterface() {
		//具体的算法实现
		return 0.0;
	}

}


四.策略模式的实例应用--商场价格打折

/**
 * @author 紫竹
 * @function 策略模式实例
 * 	演示商场打折:  a.对于普通客户或者是新客户报全价
 * 			  b.对于老客户报的价格,统一折扣5%
 * 			  c.对于大客户报的价格,统一折扣10%
 */
package com.model;

import com.interfaces.Strategy;

//计算价格类
public class Price {
	private Strategy strategy=null;
	public Price(){
		
	}
	public Price(Strategy strategy) {
		super();
		this.strategy = strategy;
	}
	
	//根据不同的具体实现的策略,得到不同的价格
	public double getCustomPrice(double goodsPrice){
		return strategy.discountPrice(goodsPrice);
	}

	public Strategy getStrategy() {
		return strategy;
	}

	public void setStrategy(Strategy strategy) {
		this.strategy = strategy;
	}
	
}

package com.interfaces;

public interface Strategy {
	double discountPrice(double goodsPrice);
}
package com.model;

import com.interfaces.Strategy;

//大客户打折的策略具体实现
public class LargeCustomStrategy implements Strategy {

	@Override
	public double discountPrice(double goodsPrice) {
		return goodsPrice*(1-0.1);
	}
	
}
package com.model;

import com.interfaces.Strategy;

//老客户打折的策略具体实现
public class OldCustomStrategy implements Strategy {

	@Override
	public double discountPrice(double goodsPrice) {
		return goodsPrice*(1-0.05);
	}
	
}
package com.test;

import com.model.*;
import com.model.Price;
//客户端测试
public class Client {
	public static void main(String args[]){
		double goodsPrice=302.23;
		Price price=new Price(new LargeCustomStrategy());
		System.out.println("大客户购买商品的价格为:"+price.getCustomPrice(goodsPrice));
		//不需要修改原来的Price 和 Strategy组合,只需要增加具体的策略即可,正好符合 开-闭的原则
		price.setStrategy(new OldCustomStrategy());
		System.out.println("老客户购买商品的价格为:"+price.getCustomPrice(goodsPrice));
	
	}
}

输出结果:

大客户购买商品的价格为:272.007
老客户购买商品的价格为:287.1185


五.模拟JDK中的策略模式实现(comparable&comparator接口)

package com.interfaces;

//comparable接口
public interface Comparable {
	int compareTo(Object obj);
}
package com.interfaces;

//comparator接口
public interface Comparator {
	int compare(Object obj1,Object o2);
}
package com.exercise.model;

import com.interfaces.Comparable;
import com.interfaces.Comparator;
//猫类,实现了Comparable接口
public class Cat implements Comparable{
	private int height;
	private int weight;
	
	private Comparator comparator=new CatWeightComparator();

	public Cat(int height,int weight) {
		super();
		this.height = height;
		this.weight=weight;
	}


	public void setHeight(int height) {
		this.height = height;
	}

	public int getHeight() {
		return height;
	}


	public int getWeight() {
		return weight;
	}


	public void setWeight(int weight) {
		this.weight = weight;
	}

	public Comparator getComparator() {
		return comparator;
	}

	public void setComparator(Comparator comparator) {
		this.comparator = comparator;
	}

	@Override
	public String toString(){
		return this.getWeight()+"|"+this.getWeight();
	}

	@Override
	public int compareTo(Object obj) {
		return comparator.compare(this, obj);//使用我指定的方式比较
	}
}
package com.exercise.model;

import com.interfaces.Comparator;

//猫高度的比较器,比较器的具体实现
public class CatHeightComparator implements Comparator{

	@Override
	public int compare(Object obj1, Object obj2) {
		Cat c1=(Cat)obj1;
		Cat c2=(Cat)obj2;
		if(c1.getWeight()>c2.getWeight())return 1;
		else if(c1.getWeight()<c2.getWeight())return -1;
		else return 0;
	}
	
}
package com.exercise.model;

import com.interfaces.Comparator;

//猫重量的比较器
public class CatWeightComparator implements Comparator{
	
	@Override
	public int compare(Object obj1, Object obj2) {
		Cat c1=(Cat)obj1;
		Cat c2=(Cat)obj2;
		if(c1.getWeight()>c2.getWeight())return 1;
		else if(c1.getWeight()<c2.getWeight())return -1;
		else return 0;
	}
	
}

package com.exercise.model;

import com.interfaces.Comparable;

//数据排序
public class DataSort{
	//冒泡排序,整数排序
	public static void sort(int [] a) {
		for(int i=0;i<a.length-1;i++){
			for(int j=0;j<a.length-i-1;j++){
				if(a[j]>a[j+1]){
					swap(a,j,j+1);
				}
			}
		}
	}	
	
	//交换
	private static void swap(int[] a, int j, int i) {
		int temp=a[j];
		a[j]=a[j+1];
		a[j+1]=temp;
	}
	
	public static void show(int [] a){
		for(int value:a){
			System.out.print(value+"\t");
		}
	}
	
	
	//冒泡排序,使用comparable接口实现对任意对象排序(这个对象必须实现Comparable接口)
	public static void sort(Object [] a) {
		for(int i=0;i<a.length-1;i++){
			for(int j=0;j<a.length-i-1;j++){				
				if(((Comparable)a[j]).compareTo((Comparable)a[j+1])==1){//大于
					swap(a,j,j+1);
				}
			}
		}
	}
	
	//交换
	private static void swap(Object[] a, int j, int i) {
		Object temp=a[j];
		a[j]=a[j+1];
		a[j+1]=temp;
	}
	//显示
	public static void show(Object [] a){
		for(Object value:a){
			System.out.print(value+"\t");
		}
	}

}
package com.exercise.test;

import com.exercise.model.Cat;
import com.exercise.model.DataSort;

//测试类
public class Test {
	public static void main(String[] args) {
//		int []a ={3,2,1,45,32,6};
		Cat cat[]={new Cat(2,2),new Cat(3,3),new Cat(8,8),new Cat(5,5),new Cat(4,4)};
		DataSort.sort(cat);
		DataSort.show(cat);
	}

}

输出结果:

2|2 3|3 4|4 5|5 8|8

本文参考了《研磨设计模式》一书,以及马士兵老师的视频,特此声明!


本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

策略模式(Strategy) 的相关文章

  • Swift 中的字典是否应该转换为类或结构?

    我正在开发一个本机 iOS 应用程序 该应用程序从我们也可以控制的 Web 服务接收 JSON 格式的数据 该计划是在大约 18 个月内更换后端数据库 以支持不同的平台 考虑到这一点 我们希望确保 iOS 应用程序能够相对容易地适应新的数据
  • 是否可以使用打字稿映射类型来创建接口的非函数属性类型?

    所以我正在研究 Typescript 的映射类型 是否可以创建一个接口来包装另一种类型 从而从原始类型中删除函数 例如 interface Person name string age number speak void type Data
  • 无法实例化类对象的类型 (Java)

    这是我收到错误的代码 在 new 之后的第二个 Killer 处 String classes new String 5 kills 0 Brian Moser kills 1 James Doakes kills 2 Lila Tourn
  • SWI-Prolog 中的跨模块“接口”调用

    这可能是 SWI Prolog 模块系统特有的 假设我们有三个 Prolog 模块 在 SWI Prolog 模块系统中 robin 在文件中robin pl arthur 在文件中arthur pl helper 在文件中helper p
  • 为什么 __dict__ 和 __weakref__ 类从未在 Python 中重新定义?

    类创建似乎从来没有re 定义 dict and weakref class属性 即 如果它们已经存在于超类的字典中 则它们不会添加到其子类的字典中 但始终re 定义 doc and module class属性 为什么 gt gt gt c
  • 如何计算嵌套对象的深度?

    我有一个嵌套对象的示例数组 let arr id 0 children id 1 children id 2 children id 3 children id 4 children 我需要计算每个对象的深度级别 在所有对象中我也有一个pa
  • TypeScript - 如何从方法的参数推断类泛型类型?

    我正在尝试从稍后调用的方法参数中输入类泛型 在我们调用带有泛型参数的方法之前 类的泛型类型是不知道的 然后 对于任何其他方法 将传递泛型类型 老实说 对我来说 这似乎是一个非常复杂的功能 我什至不确定 TypeScript 是否有办法做到这
  • 具体实现是否应该提供其实现的接口中不存在的任何公共 API?

    接口代码 被认为是很好的实践 这样的代码很容易进行单元测试并实现松散耦合 用户只知道接口 并且连接具体对象的责任位于最顶层 这可以在某些初始化代码中或在帮助下完成 框架 我的问题是关于遵循以下做法代码到接口 这是否意味着具体类永远不能声明其
  • C++dynamic_cast vs 在静态枚举中存储对象类型?

    我正在为一个框架开发一个大的类层次结构 完成后将需要大量的类型转换 我的问题是 放入一个使用枚举来存储层次结构中所有对象类型的静态成员是多么愚蠢的想法 让每个类的成员都是静态的不会增加实例化对象的大小 并且会提供一种 可能 比dynamic
  • 多个 WCF 服务实现相同的服务契约接口

    多个wcf服务是否可以实现同一个服务契约接口 我想要做的是允许测试服务与真实服务互换 并指定在配置文件中使用哪个服务 例如 ServiceContract public interface IUselessService Operation
  • 为什么方法引用不跟踪这一点?

    我正在使用 Babel 来转译 ES2015 类 class Foo constructor foo this foo foo sayFoo console log this foo 如果我说这样的话 这个课程的效果就完全符合我的预期foo
  • SwiftUI - 使用“ObservableObject”和@EnvironmentObject 有条件地显示视图

    我想在我的应用程序中有条件地显示不同的视图 如果某个布尔值为 true 则将显示一个视图 如果为 false 将显示不同的视图 该布尔值位于 ObservableObject 类中 并根据将要显示的视图之一进行更改 PracticeStat
  • 为什么非空槽不能与 int、tuple、bytes 子类一起使用?

    参考手册中明确记录了这一点 非空 slots 不适用于从 可变长度 内置类型 例如 int bytes 和 tuple 派生的类 情况确实如此 写道 class MyInt int slots spam 结果是 TypeError none
  • __del__ 上的 Python 属性错误

    我有一个 python 类对象 我想分配一个类变量的值 class Groupclass Workerclass worker class count 0 def init self initialize time Groupclass c
  • 比较 C# 中的对象属性[关闭]

    Closed 这个问题是基于意见的 help closed questions 目前不接受答案 Locked 这个问题及其答案是locked help locked posts因为这个问题是题外话 但却具有历史意义 目前不接受新的答案或互动
  • 使用带有通配符的 jquery grep 搜索对象数组

    我正在使用 jquery grep 搜索对象数组 并希望在搜索中包含通配符 例如 我有一个数组如下 courses code ENCH3TH otherFields otherStuff code ENCH3THHS1 otherField
  • 将带有 **kwargs 错误的值线程化并传递给 TypeError

    我对 Python 还很陌生 并且正在通过这篇文章研究如何使用线程来处理某些代码 Python 使用线程或队列迭代调用函数的 for 循环 https stackoverflow com questions 12868956 python
  • 不同 C++ 文件中的相同类名

    如果两个 C 文件具有相同名称的类的不同定义 那么当它们被编译和链接时 即使没有警告也会抛出一些东西 例如 a cc class Student public std string foo return A void foo a Stude
  • 不可变类与结构

    以下是类与 C 中的结构的唯一区别 如果我错了 请纠正我 类变量是引用 而结构变量是值 因此在赋值和参数传递中复制结构的整个值 类变量是存储在堆栈上的指针 指向堆上的内存 而结构变量作为值存储在堆上 假设我有一个不可变的结构 该结构的字段一
  • Java 中序列化的目的是什么?

    我读过很多关于序列化的文章 以及它如何如此美好和伟大 但没有一个论点足够令人信服 我想知道是否有人能真正告诉我通过序列化一个类我们真正可以实现什么 让我们先定义序列化 然后我们才能讨论它为什么如此有用 序列化只是将现有对象转换为字节数组 该

随机推荐

  • electron --unsafely-treat-insecure-origin-as-secure 问题解决 navigator.mediaDevices = undefined

    问题原因 由于electron mainWindow loadURL http 127 0 0 1 访问是已http协议 而chrome浏览器在访问http请求时考虑隐私安全是无法打开许多Web API的 如 navigator media
  • 求字符串可匹配的最大长度

    如 text abcdlijkfgd query abcdefg 最大匹配为 abcd 为4 编写一个函数 求字符串可匹配的最大长度 如果是完全匹配 则用很多种方法 如BF KMP sunday等字符串匹配算法 KMP是比较常见的 其思想也
  • 软件项目管理的成功法则

    1 平衡原则 在我们讨论软件项目为什么会失败时可以列出了很多的原因 答案有很多 如管理问题 技术问题 人员问题等等 但是有一个根本的思想问题是最容易忽视的 也是软件系统的用户 软件开发商 销售代理商最不想正视的 那就是 需求 资源 工期 质
  • Jmeter之响应断言

    断言有很多种 最最最常用的一种就是响应断言 目前我也只接触过这么一种 详情 Main sample and sub samples 断言应用于主采样器和子采样器 Main sample only 断言仅应用于主采样器 Sub samples
  • 排序算法的稳定与不稳定

    稳定的排序算法 通俗地讲就是能保证排序前2个相等的数其在序列的前后位置顺序和排序后它们两个的前后位置顺序相同 在简单形式化一下 如果Ai Aj Ai原来在位置前 排序后Ai还是要在Aj位置前 没错 其实就是有两个排序关键字的时候 稳定排序可
  • 2023华为OD机试真题-数字加减游戏(JAVA、Python、C++)

    题目描述 小明在玩一个数字加减游戏 只使用加法或者减法 将一个数字s变成数字t 每个回合 小明可以用当前的数字加上或减去一个数字 现在有两种数字可以用来加减 分别为 其中b没有使用次数限制 请问小明最少可以用多少次a 才能将数字s变成数字t
  • 我所不知道的TCP Socket编程(五)-交换数据、套接字读写操作

    五 交换数据 已经建立了服务器和客户端的链接 现在需要让它们进行数据交换 你可以将TCP连接想象成一串连接了本地套接字和远程套接字的管子 我们可以沿着这个管子发送和接受数据 实际中 数据被编码为TCP IP分组 经过多台路由器和主机 抵达终
  • 使用YOLOv5模型进行目标检测!

    点击上方 小白学视觉 选择加 星标 或 置顶 重磅干货 第一时间送达 目标检测是计算机视觉领域的一大任务 大致分为一阶段目标检测与两阶段目标检测 其中一阶段目标检测模型以YOLO系列为代表 最新的YOLOv5在各个数据集上体现出收敛速度快
  • 实现Excel的导入、导出

    实现Excel的导入 导出 关于excel的操作在工作中经常会遇到 如果只是一次性使用的话 最简单的方式就是通过数据库的可视化工具 如Navicat 查询结果集之后直接一键生成excel了 当然这只能解燃眉之急 并不是长久之计 首先Exce
  • PAT C入门题目-7-12 日期格式化 (5 分)

    7 12 日期格式化 5 分 世界上不同国家有不同的写日期的习惯 比如美国人习惯写成 月 日 年 而中国人习惯写成 年 月 日 下面请你写个程序 自动把读入的美国格式的日期改写成中国习惯的日期 输入格式 输入在一行中按照 mm dd yyy
  • 小车+摄像头 +ros+gazebo+yolo仿真

    一 项目代码下载 https blog csdn net WhiffeYF article details 109187804 下载到 catkin ws2 src 中 这几个文件 其中 darknet ros 用于yolo的目标检测 mr
  • 【关于PyCharm安装和加载Pyecharts可视化库的方法和安装过程中出现的No Module Named XXX的解决方案】

    作者 亮马桥胡歌Wechat changxu1129 Echarts 是百度开源的一个数据可视化 JS 库 主要用于数据可视化 点击访问Echarts官网 http echarts baidu com index html 点此直接访问Py
  • Telink 825x 蓝牙开发笔记1

    Telink 825x 蓝牙开发笔记1 背景 美国贸易战导致芯片等模组价格上涨 为了以后长期发展需要研究国产蓝牙 Telink 一 环境搭建 1 软件下载 IDE Telink IDE 1 3 量产工具 Telink BDT exe v5
  • robots.txt 如何禁止蜘蛛(百度,360,搜狗,谷歌)搜索引擎获取页面内容

    什么是蜘蛛抓取 搜索引擎使用spider程序自动访问互联网上的网页并获取网页信息 spider在访问一个网站时 会首先会检查该网站的根域下是否有一个叫做robots txt的纯文本文件 您可以在您的网站中创建一个纯文本文件robots tx
  • 二十一. Kubernetes 配置的创建与使用

    目录 一 配置基础 二 Secret 配置介绍与使用示例 Secret 的创建 Secret 的使用 1 pod env 中作为环境变量获取使用 Secret 2 以卷挂载的方式使用 Secret 三 ConfigMap 介绍与使用示例 C
  • 卷积神经网络「失陷」,CoordConv来填坑

    卷积神经网络 失陷 CoordConv来填坑 作者 Rosanne Liu等 卷积神经网络拥有权重共享 局部连接和平移等变性等非常优秀的属性 使其在多种视觉任务上取得了极大成功 但在涉及坐标建模的任务上 如目标检测 图像生成等 其优势反而成
  • Qt实现基于多线程的文件传输(服务端,客户端)

    1 效果 先看看效果图 这是传输文件完成的界面 客户端 服务端 2 知识准备 其实文件传输和聊天室十分相似 只不过一个传输的是文字 一个传输的是文件 而这方面的知识 我已经在前面的博客写过了 不了解的同学可以去看一下 C 网络编程 Qt实现
  • excel文件服务器未响应,excel打不开文件未响应怎么处理-处理excel无法打开文件未响应的方法 - 河东软件园...

    Excel是office组件中的一个 经常跟数据打交道的用户每天都会接触到它 有的时候我们在打开该软件的时候都会出现无法导入文件的情况 无论你使用的是哪个版本的office软件都会在打开文件的时候发现软件没有响应 一般出现这样的情况都会在左
  • C++入门(一)----Visual C++ 6.0和Visual Studio 2019 的安装与使用

    Visual C 6 0的安装与使用 下载 安装 https blog csdn net weixin 41822392 article details 89519036 使用 https blog csdn net yiminghd286
  • 策略模式(Strategy)

    一 策略模式定义 定义一系列算法 把他们封装起来 并且他们可以相互替换 本模式使得算法可独立于使用他的客户而变化 二 策略模式结构说明 1 Strategy 策略接口 用来约束一系列具体的策略算法 Context使用这个接口来调用具体的策略