设计模式-策略(Strategy)模式

  • 又被称为政策(方针)模式
  • 策略模式(Strategy Design Pattern):封装可以互换的行为,并使用委托来决定要使用哪一个
  • 策略模式是一种行为设计模式,它能让你定义一系列算法,并将每种算法分别放入独立的类中,以使算法的对象能够相互替换
  • 用人话翻译后就是:运行时我给你这个类的方法传不同的 “key”,你这个方法就去执行不同的业务逻辑
  • 解释:
    • 现实世界例子:屠龙是一项危险的职业;有经验将会使它变得简单;经验丰富的屠龙者对不同类型的龙有不同的战斗策略
    • 直白点说,策略模式允许在运行时选择最匹配的算法
    • 在程序编程领域,策略模式(又叫政策模式)是一种启用在运行时选择算法的行为型软件设计模式
  • 仔细一想,这不就是 if else 干的事吗
  • 先直观的看下传统的多重 if else 代码:

  • 再来看策略模式类图:

  • 策略模式涉及到三个角色:
    • Strategy:策略接口或者策略抽象类,用来约束一系列的策略算法(Context 使用这个接口来调用具体的策略实现算法)
    • ConcreateStrategy:具体的策略类(实现策略接口或继承抽象策略类)
    • Context:上下文类,持有具体策略类的实例,并负责调用相关的算法
  • 先来看看最简单的策略模式 demo:
  • 1-策略接口(定义策略)

  • 2-具体的算法实现

  • 3-上下文的实现

  • 4-客户端使用(策略的使用)

  • 这种策略的使用方式其实很死板,真正使用的时候如果还这么写,和写一大推 if-else 没什么区别,所以我们一般会结合工厂类,在运行时动态确定使用哪种策略
  • 策略模式侧重如何选择策略、工厂模式侧重如何创建策略
  • 策略模式的功能就是把具体的算法实现从具体的业务处理中独立出来,把它们实现成单独的算法类,从而形成一系列算法,并让这些算法可以互相替换
  • 策略模式的重心不是如何来实现算法,而是如何组织、调用这些算法,从而让程序结构更灵活,具有更好的维护性和扩展性
  • 实际上,每个策略算法具体实现的功能,就是原来在 if-else 结构中的具体实现,每个 if-else 语句都是一个平等的功能结构,可以说是兄弟关系
  • 策略模式呢,就是把各个平等的具体实现封装到单独的策略实现类了,然后通过上下文与具体的策略类进行交互
  • 策略模式 = 实现策略接口(或抽象类)的每个策略类 + 上下文的逻辑分派

  • 策略模式的本质:分离算法,选择实现
  • 所以说,策略模式只是在代码结构上的一个调整,即使用了策略模式,该写的逻辑一个也少不了,到逻辑分派的时候,只是变相的 if-else
  • 而它的优化点是抽象了出了接口,将业务逻辑封装成一个一个的实现类,任意地替换
  • 在复杂场景(业务逻辑较多)时比直接 if-else 更好维护和扩展些
  • 在策略模式中,我们可以自己定义谁来选择具体的策略算法,有两种:
    • 客户端:当使用上下文时,由客户端选择,像我们上边的 demo
    • 上下文:客户端不用选,由上下文来选具体的策略算法,可以在构造器中指定
  • 避免冗长的if/else:
    • 比如在出门旅游时:路线、交通工具的类型、天数、舱位等级、餐饮、住宿等等
    • 每个节点在执行时,都需要根据预算进行不同的操作,从而引起大量的判断
    • 增加一个策略,修改一个策略,都有可能牵一发而动全身
    • 需要对所有状态进行回测

    • 整个业务如图所示,所有的判断都耦合在业务流程内部,牵一发而动全身

    • 使用策略模式
    • 我们可以将某一条件(Type)下的逻辑,聚合封装到具体的策略类中

    • 使用策略类后如图所示,每个的情况被封装聚合到单个策略类中,相互隔离

    • 所以策略模式的作用主要体现在:
      • 1-解耦策略的定义、创建和使用
      • 控制代码的复杂度,让每个部分都不至于过于复杂、代码量过多
      • 2-让复杂框架满足开闭原则
      • 添加或者修改新策略的时候,最小化、集中化代码改动,减少引入 bug 的风险
    • 策略的创建
    • 通常会通过类型(type)来判断创建哪个策略来使用
    • 这里,有两种创建方式
      • if-else创建
      • 适用于有状态的策略类,每次创建一个新的策略类给业务方使用

      • 通过工厂模式里的Map进行创建
      • 适用于无状态的策略类创建,大家共用一个策略类即可

      • 本质上讲,是借助“查表法”,根据 type 查表替代根据 type 分支判断
  • Java中的例子:
    • 采用 Comparator 参数的 Collections.sort() 方法;根据 Comparator 接口的不同实现,对象会以不同的方式进行排序
  • 使用策略模式应当:
    • 许多相关的类只是行为不同;策略模式提供了一种为一种类配置多种行为的能力
    • 你需要一种算法的不同变体;比如,你可能定义反应不用时间空间权衡的算法;当这些算法的变体使用类的层次结构来实现时就可以使用策略模式
    • 一个算法使用的数据客户不应该对其知晓;使用策略模式来避免暴露复杂的,特定于算法的数据结构
    • 一个类定义了许多行为,这些行为在其操作中展现为多个条件语句;移动相关的条件分支到它们分别的策略类中来代替这些条件语句

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

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

相关文章

[MySQL]数据库概述

目录 1.什么是数据库 2.数据库分类 2.1关系型数据库 2.2非关系型数据库 1.什么是数据库 我们知道,存储数据可以使用文件来存储。那么为什么我们还要大费周章的去设计和使用数据库呢? 因为文件保存数据有以下几个缺点: 1.文件的安全性不…

浅谈MapReduce

MapReduce是一个抽象的分布式计算模型,主要对键值对进行运算处理。用户需要提供两个自定义函数: map:用于接受输入,并生成中间键值对。reduce:接受map输出的中间键值对集合,进行sorting后进行合并和数据规…

clickhouse函数记录

日期函数 SELECT formatDateTime(create_time,%Y-%m-%d) AS time FROM xx.xx;

安路IP核应用举例(OSC、UART)

1.OSC(内部振荡器) 按照Project->New Project顺序新建工程后,后按照Tools->IP Generator顺序,创建IP核,如下图: 安路FPGA的内置OSC振荡模块频率可选30MHz、60MHz。 可选Verilog或VHDL语言。 如图,生成的.v文件只…

【Linux】内核结构

一、Linux内核结构介绍 Linux内核结构框图 二、图解Linux系统架构 三、驱动认知 1、为什么要学习写驱动2、文件名与设备号3、open函数打通上层到底层硬件的详细过程 四、Shell Shell脚本 一、Linux内核结构介绍 Linux 内核是操作系统的核心部分,它负责管理系…

“Java 已死、前端已凉”?技术变革与编程语言前景:Java和前端的探讨

前端已死话题概论 本文讨论了近期IT圈中流传的“Java 已死、前端已凉”言论。我们审视了这些言论的真实性,并深入探讨了技术行业的演变和新兴技术的出现对编程语言和前端开发的影响。通过分析历史发展、当前趋势和未来展望,我们提供了对这些话题更深层次…

HBuilderX 配置 夜神模拟器 详细图文教程

在电脑端查看App的效果,不用真机调试,下载一个模拟器就可以了 --- Nox Player,夜神模拟器,是一款 Android 模拟器。他的使用非常安全,最重要的是完全免费。 一. 安装模拟器 官网地址: (yeshen.com) 二.配…

探索性能测试的奥秘:流程与工具大揭秘!

一、性能测试 性能测试是通过自动化的测试工具模拟多种正常、峰值以及异常负载条件来对系统的各项性能指标进行测试。 1.1 类别 性能测试包括负载测试、压力测试、基准测试等。 1.1.1 负载测试 通过测试系统在资源超负荷情况下的表现,以发现设计上的错误或验证…

【MYSQL】事务隔离级别、脏读、不可重复读、幻读

文章目录 介绍演示脏读不可重复读可重复读幻读 不可重复读和幻读的区别 参考 作者 Guide: 事务隔离级别 美团技术团队: Innodb中的事务隔离级别和锁的关系 介绍 SQL 标准定义了四个隔离级别: READ-UNCOMMITTED(读取未提交) :最低的隔离级别…

论文阅读——Semantic-SAM

Semantic-SAM可以做什么: 整合了七个数据集: 一般的分割数据集,目标级别分割数据集:MSCOCO, Objects365, ADE20k 部分分割数据集:PASCAL Part, PACO, PartImagenet, and SA-1B The datasets are SA-1B, COCO panopt…

java简易制作-王者荣耀游戏

一.准备工作 首先创建一个新的Java项目命名为“王者荣耀”,并在src下创建两个包分别命名为“com.sxt"、”com.stx.beast",在相应的包中创建所需的类。 创建一个名为“img”的文件夹来储存所需的图片素材。 二.代码呈现 package com.sxt; import javax…

【设计模式--行为型--观察者模式】

设计模式--行为型--观察者模式 观察者模式定义结构案例优缺点使用场景JDK中提供的实现例:警察抓小偷 观察者模式 定义 又被成为发布订阅模式,它定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态发生…

INFINI Labs 产品更新 | Easysearch 新增快照搜索功能,Console 支持 OpenSearch 存储

INFINI Labs 产品又更新啦~,包括 Easysearch v1.7.0、Console v1.13.0。本次各产品更新了 Easysearch 快照搜索功能;Console 支持 OpenSearch 集群存储系统数据、优化了初始化安装向导流程等。 以下是本次更新的详细说明。 INFINI Easysearch v1.7.0 …

遥感论文 | ISPRS | 图神经网络也能做城市街道功能感知?纯视觉方案,效果可观!

论文题目:Knowledge and topology: A two layer spatially dependent graph neural networks to identify urban functions with time-series street view image论文网址:https://www.sciencedirect.com/science/article/pii/S0924271623000680论文代码&…

【lesson16】进程控制之进程替换(1)

文章目录 进程替换是什么?进程替换怎么用?不创建子进程时使用 进程替换是什么? 我们知道fork()之后,父子进程各自执行父进程的一部分代码,如果子进程就想执行一个全新的程序呢? 以前:父子代码…

K8S(二)—介绍

K8S的整体结构图 k8s对象 在 Kubernetes 系统中,Kubernetes 对象是持久化的实体。 Kubernetes 使用这些实体去表示整个集群的状态。 具体而言,它们描述了如下信息: 哪些容器化应用正在运行(以及在哪些节点上运行)可…

微服务实战系列之ZooKeeper(中)

前言 昨日博主的第一篇ZooKeeper,对它自身具备的能力做了初步介绍。书接上文,马不停蹄,我们继续挖掘它内在的美,充分把握它的核心与脉络。 揭秘ZooKeeper Q:集群一致性协同是如何进行的 我们讲到分布式,…

Renyi散度:Renyi divergence

有关Renyi散度的基本介绍挺多博客已经写了。本文章主要介绍最基础的概念,以及近些年论文中为啥老喜欢引用这个概念。 一.基础概念 Renyi散度主要是描述两个分布之间的关系。对一个离散的概率分布X,其定义域记作,其实就是概率不为零的点的集…

React脚手架搭建

React脚手架 脚手架:可以快速构建项目的基本架构。 脚手架安装命令 可全局安装脚手架 创建项目 来到当前目录下 create-react-app 项目名(不要大写字母) 运行项目 进到项目里,在项目目录下,执行 npm start &#xff…

C语言-Makefile

Makefile 什么是make? make 是个命令,是个可执行程序,用来解析 Makefile 文件的命令这个命令存放在 /usr/bin/ 什么是 makefile? makefile 是个文件,这个文件中描述了我们程序的编译规则咱们执行 make 命令的时候, m…