设计模式之策略模式【行为型模式】

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档> 学习的最大理由是想摆脱平庸,早一天就多一份人生的精彩;迟一天就多一天平庸的困扰。各位小伙伴,如果您:
想系统/深入学习某技术知识点…
一个人摸索学习很难坚持,想组团高效学习…
想写博客但无从下手,急需写作干货注入能量…
热爱写作,愿意让自己成为更好的人…

文章目录

  • 前言
  • 一、概述
  • 二、结构
  • 三、案例实现
  • 四、优缺点
  • 五、使用场景
  • 六、JDK源码解析
  • 总结


前言

一、概述
二、结构
三、案例实现
四、优缺点
五、使用场景
六、JDK源码解析


一、概述

先看下面的图片,我们去旅游选择出行模式有很多种,可以骑自行车、可以坐汽车、可以坐火车、可以坐飞机。
在这里插入图片描述
作为一个程序猿,开发需要选择一款开发工具,当然可以进行代码开发的工具有很多,可以选择Idea进行开发,也可以使用eclipse进行开发,也可以使用其他的一些开发工具。
在这里插入图片描述
定义:

​ 该模式定义了一系列算法,并将每个算法封装起来,使它们可以相互替换,且算法的变化不会影响使用算法的客户。策略模式属于对象行为模式,它通过对算法进行封装,把使用算法的责任和算法的实现分割开来,并委派给不同的对象对这些算法进行管理。

二、结构

策略模式的主要角色如下:

  • 抽象策略(Strategy)类:这是一个抽象角色,通常由一个接口或抽象类实现。此角色给出所有的具体策略类所需的接口。
  • 具体策略(Concrete Strategy)类:实现了抽象策略定义的接口,提供具体的算法实现或行为。
  • 环境(Context)类:持有一个策略类的引用,最终给客户端调用。

三、案例实现

【例】促销活动

一家百货公司在定年度的促销活动。针对不同的节日(春节、中秋节、圣诞节)推出不同的促销活动,由促销员将促销活动展示给客户。类图如下:
在这里插入图片描述
代码如下:

定义百货公司所有促销活动的共同接口

//抽象策略类
public interface Strategy {void show();
}

定义具体策略角色(Concrete Strategy):每个节日具体的促销活动

//为春节准备的促销活动A
public class StrategyA implements Strategy {public void show() {System.out.println("买一送一");}
}//为中秋准备的促销活动B
public class StrategyB implements Strategy {public void show() {System.out.println("满200元减50元");}
}//为圣诞准备的促销活动C
public class StrategyC implements Strategy {public void show() {System.out.println("满1000元加一元换购任意200元以下商品");}
}

定义环境角色(Context):用于连接上下文,即把促销活动推销给客户,这里可以理解为销售员

//促销员【环境类】聚合策略类
public class SalesMan {//持有抽象策略角色的引用,聚合策略类对象private Strategy strategy;                 public SalesMan(Strategy strategy) {       this.strategy = strategy;              }                                          //向客户展示促销活动                                public void salesManShow(){                strategy.show();                       }                                          
}                                                

Client 类

public class Client {public static void main(String[] args) {//春节来了,使用春节促销活动SalesMan salesMan=new SalesMan(new StrategyA());//展示促销活动salesMan.salesManShow();System.out.println("================");//中秋节到了SalesMan salesMan1=new SalesMan(new StrategyB());salesMan1.salesManShow();System.out.println("================");//圣诞节到了SalesMan salesMan2=new SalesMan(new StrategyC());salesMan2.salesManShow();}
}

在这里插入图片描述

四、优缺点

1,优点:

  • 策略类之间可以自由切换

    由于策略类都实现同一个接口,所以使它们之间可以自由切换。

  • 易于扩展

    增加一个新的策略只需要添加一个具体的策略类即可,基本不需要改变原有的代码,符合“开闭原则“

  • 避免使用多重条件选择语句(if else),充分体现面向对象设计思想。

2,缺点:

  • 客户端必须知道所有的策略类,并自行决定使用哪一个策略类。
  • 策略模式将造成产生很多策略类,可以通过使用享元模式在一定程度上减少对象的数量。

五、使用场景

  • 一个系统需要动态地在几种算法中选择一种时,可将每个算法封装到策略类中。
  • 一个类定义了多种行为,并且这些行为在这个类的操作中以多个条件语句的形式出现,可将每个条件分支移入它们各自的策略类中以代替这些条件语句。
  • 系统中各算法彼此完全独立,且要求对客户隐藏具体算法的实现细节时。
  • 系统要求使用算法的客户不应该知道其操作的数据时,可使用策略模式来隐藏与算法相关的数据结构。
  • 多个类只区别在表现行为不同,可以使用策略模式,在运行时动态选择具体要执行的行为。

六、JDK源码解析

Comparator 中的策略模式。在Arrays类中有一个 sort() 方法,如下:

public class Arrays{public static <T> void sort(T[] a, Comparator<? super T> c) {if (c == null) {sort(a);} else {if (LegacyMergeSort.userRequested)legacyMergeSort(a, c);elseTimSort.sort(a, 0, a.length, c, null, 0, 0);}}
}

Arrays就是一个环境角色类,这个sort方法可以传一个新策略让Arrays根据这个策略来进行排序。就比如下面的测试类。

public class demo {public static void main(String[] args) {Integer[] data = {12, 2, 3, 2, 4, 5, 1};// 实现降序排序Arrays.sort(data, new Comparator<Integer>() {public int compare(Integer o1, Integer o2) {return o2 - o1;}});System.out.println(Arrays.toString(data)); //[12, 5, 4, 3, 2, 2, 1]}
}

这里我们在调用Arrays的sort方法时,第二个参数传递的是Comparator接口的子实现类对象。所以Comparator充当的是抽象策略角色,而具体的子实现类充当的是具体策略角色。环境角色类(Arrays)应该持有抽象策略的引用来调用。那么,Arrays类的sort方法到底有没有使用Comparator子实现类中的 compare() 方法吗?让我们继续查看TimSort类的 sort() 方法,代码如下:

class TimSort<T> {static <T> void sort(T[] a, int lo, int hi, Comparator<? super T> c,T[] work, int workBase, int workLen) {assert c != null && a != null && lo >= 0 && lo <= hi && hi <= a.length;int nRemaining  = hi - lo;if (nRemaining < 2)return;  // Arrays of size 0 and 1 are always sorted// If array is small, do a "mini-TimSort" with no mergesif (nRemaining < MIN_MERGE) {int initRunLen = countRunAndMakeAscending(a, lo, hi, c);binarySort(a, lo, hi, lo + initRunLen, c);return;}...}   private static <T> int countRunAndMakeAscending(T[] a, int lo, int hi,Comparator<? super T> c) {assert lo < hi;int runHi = lo + 1;if (runHi == hi)return 1;// Find end of run, and reverse range if descendingif (c.compare(a[runHi++], a[lo]) < 0) { // Descendingwhile (runHi < hi && c.compare(a[runHi], a[runHi - 1]) < 0)runHi++;reverseRange(a, lo, runHi);} else {                              // Ascendingwhile (runHi < hi && c.compare(a[runHi], a[runHi - 1]) >= 0)runHi++;}return runHi - lo;}
}

上面的代码中最终会跑到 countRunAndMakeAscending() 这个方法中。我们可以看见,只用了compare方法,所以在调用Arrays.sort方法只传具体compare重写方法的类对象就行,这也是Comparator接口中必须要子类实现的一个方法。


总结

以上就是设计模式之策略模式【行为型模式】的相关知识点,希望对你有所帮助。
积跬步以至千里,积怠惰以至深渊。时代在这跟着你一起努力哦!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/345802.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

代码随想录 Leetcode142. 环形链表 II

题目&#xff1a; 代码(首刷看解析 2024年1月13日&#xff09;&#xff1a; class Solution { public:ListNode *detectCycle(ListNode *head) {if (head nullptr) return nullptr;ListNode* fast head;ListNode* slow head;while (true) {if(fast->next nullptr || fa…

Binder 机制 javanative

一&#xff1a;Binder介绍 Binder是一套ipc通信方案 Binder框架定义了四个角色&#xff1a; Server &#xff0c;Client&#xff0c;ServiceManager &#xff08;以后简称SMgr&#xff09;以及Binder驱动。其中Server &#xff0c;Client&#xff0c;SMgr运行于用户空间&#…

Modbus协议

一.起源 Modbus由Modicon公司于1979年开发&#xff0c;是一种工业现场总线协议标准。Modbus通信协议具有多个变种&#xff0c;其中有支持串口&#xff0c;以太网多个版本&#xff0c;其中最著名的是Modbus RTU、Modbus ASCII和Modbus TCP三种。其中Modbus TCP是在施耐德收购Mo…

LeetCode讲解篇之39. 组合总和

文章目录 题目描述题解思路题解代码 题目描述 题解思路 首先排序数组&#xff0c;然后开始选择数字&#xff0c;当选择数字num后&#xff0c;在去选择大于等于num的合法数字&#xff0c;计算过程中的数字和&#xff0c;直到选数字和等于target, 加入结果集&#xff0c;若数字和…

FreeRTOS 基础知识

这个基础知识也是非常重要的&#xff0c;那我们要学好 FreeRTOS&#xff0c;这些都是必不可少的。 那么就来看一下本节有哪些内容&#xff1a; 首先呢就是介绍一下什么是任务调度器。接着呢就是任务它拥有哪一些状态了。那这里的内容不多&#xff0c;但是呢都是非常重要的。 …

C语言——内存函数【memcpy,memmove,memset,memcmp】

&#x1f4dd;前言&#xff1a; 在之前的文章C语言——字符函数和字符串函数&#xff08;一&#xff09;中我们学习过strcpy和strcat等用来实现字符串赋值和追加的函数&#xff0c;那么除了字符内容&#xff0c;其他的数据&#xff08;例如整型&#xff09;能否被复制或者移动呢…

maya显示方式及视图操作

原始图像&#xff1a; 按数字键2后&#xff08;平滑效果&#xff09;&#xff1a; 按数字键3后&#xff08;平滑效果&#xff0c;无原始外边框&#xff09;&#xff1a; 按数字键4后&#xff08;仅显示边框&#xff09;&#xff1a; 方便选择后面的点、线及面 按数字键5后&…

java多线程(并发)夯实之路-进程与线程深入浅出

进程与线程介绍 进程 程序由指令和数据组成&#xff0c;程序工作时&#xff0c;就会将指令加载至CPU&#xff0c;数据加载至内存&#xff0c;进程就是用来加载指令&#xff0c;管理内存&#xff0c;管理IO的。 当程序运行&#xff0c;磁盘加载这个程序的代码至内存&#xff0c;…

应用在游戏机触摸屏中的触摸感应芯片

触屏游戏机的屏幕是由液晶屏和触控层组成的。触控层分为电容式触屏和电阻式触屏两种。电容式触屏是将悬空电极和屏幕玻璃上的电极组成静电场,当人体接近屏幕时,就会改变静电场分布,从而实现触摸的位置探测。而电阻式触屏则是利用玻璃上的两层电极之间通电形成一个电阻值,当手指…

【PHP AES加解密示例】从入门到精通,一篇文章让你掌握加密解密技术!

一、引言 随着互联网的普及&#xff0c;数据安全问题越来越受到人们的关注。在众多加密算法中&#xff0c;AES&#xff08;Advanced Encryption Standard&#xff09;因其高效、安全的特点被广泛应用。本文将通过PHP语言&#xff0c;为大家展示一个简单的AES加解密示例&#x…

计算机毕业设计-----SSH在线电影售票选座版网站平台系统

项目介绍 本项目为前后台项目&#xff0c;首先分为管理员和普通用户&#xff0c;游客。 游客可以进入首页&#xff0c;必须注册成为普通用户才能进行影片的购买。管理员和普通用户进行分权限登录&#xff0c;登录后进入不同页面。 普通用户登录后进入首页&#xff0c;首页有影…

手把手教你用 Stable Diffusion 写好提示词

Stable Diffusion 技术把 AI 图像生成提高到了一个全新高度&#xff0c;文生图 Text to image 生成质量很大程度上取决于你的提示词 Prompt 好不好。 前面文章写了一篇文章&#xff1a;一份保姆级的 Stable Diffusion 部署教程&#xff0c;开启你的炼丹之路 本文从“如何写好…