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

news2024/7/6 18:59:58

学习汇总入口【23种设计模式】学习汇总(数万字讲解+体系思维导图)

一.概述

该模式定义了一系列算法,并将每个算法封装起来,使它们可以相互替换,且算法的变化不会影响使用算法的客户。

策略模式属于对象行为模式,它通过对算法进行封装,把使用算法的责任和算法的实现分割开来,并委派给不同的对象对这些算法进行管理。

例如先看下面的图片,我们去旅游选择出行模式有很多种,可以骑自行车、可以坐汽车、可以坐火车、可以坐飞机。

作为一个程序猿,开发需要选择一款开发工具,当然可以进行代码开发的工具有很多,可以选择Idea进行开发,也可以使用eclipse进行开发,也可以使用其他的一些开发工具。

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

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

二.使用

(1) 案例

【例】促销活动

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

代码如下:

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

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();                       
    }                                          
}                                              

(2) 优缺点

  • 优点

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

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

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

  • 缺点

    • 客户端必须知道所有的策略类,并自行决定使用哪一个策略类。

    • 策略模式将造成产生很多策略类,可以通过使用享元模式在一定程度上减少对象的数量。

(3) 使用场景

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

三.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);
            else
                TimSort.sort(a, 0, a.length, c, null, 0, 0);
        }
    }
}

Arrays就是一个环境角色类,这个sort方法可以传一个新策略Comparator让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 merges
        if (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 descending
        if (c.compare(a[runHi++], a[lo]) < 0) { // Descending
            while (runHi < hi && c.compare(a[runHi], a[runHi - 1]) < 0)
                runHi++;
            reverseRange(a, lo, runHi);
        } else {                              // Ascending
            while (runHi < hi && c.compare(a[runHi], a[runHi - 1]) >= 0)
                runHi++;
        }

        return runHi - lo;
    }
}

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

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

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

相关文章

英语学习 作文 1

1 议论文和应用文 1、议论文&#xff1a;essay 1 观点选择&#xff1a;option、choice 2 现象解释&#xff1a;why、what 3 问题解决&#xff1a;how to、solution、measure **4 图片图表&#xff1a;image、cartoon、diagram、chart**2、应用文&#xff1a;信件、通知、报道…

设计模式——创建型模式

目录 4.创建型模式 4.1 单例设计模式 4.1.1 单例模式的结构 4.1.2 单例模式的实现 4.1.3 存在的问题 4.1.4 JDK源码解析-Runtime类 4.2 工厂模式 4.2.1 概述 4.2.2 简单工厂模式 4.2.3 工厂方法模式 4.2.4 抽象工厂模式 4.2.5 模式扩展 4.2.6 JDK源码解析-Collecti…

2023年山东最新建筑施工信号工(建筑特种作业)考试真题题库及答案

百分百题库提供特种工&#xff08;信号工&#xff09;考试试题、特种工&#xff08;信号工&#xff09;考试预测题、特种工&#xff08;信号工&#xff09;考试真题、特种工&#xff08;信号工&#xff09;证考试题库等,提供在线做题刷题&#xff0c;在线模拟考试&#xff0c;助…

C++98以及C++11产生随机数的方法

目录引言1、C98标准实现随机数2、C11新标准随机数引擎引言 在C11出现之前&#xff0c;C98使用随机数采用的是C标准库的写法。而在C11出现后&#xff0c;我们生成随机数可以采用更为现代化的方式。 1、C98标准实现随机数 以往生成随机数使用的是cstdlib.h库中的rand()函数&…

基于Node.js的3DTiles三维倾斜摄影模型爬虫

随着小型无人机的普及,乡村级的倾斜摄影模型构建已经越来越简单。一个无人机和一名飞手2个小时内就可以完成。在做WebGIS和Cesium开发时,3DTiles是一种常用的倾斜摄影三维模型的切片格式。3DTiles格式通常有散列和紧凑两种文件组织形式,其中不同工具生成的散列数据使用的索引…

【GNN报告】GNN-LOGS部分报告汇总

Bastain Rieck: Topology-Based Graph Representation Learning 基础 拓扑学习 基于拓扑学习的工作 参考 Bastain Rieck: Topology-Based Graph Representation Learning_哔哩哔哩_bilibili Chaitanya K. Joshi Graph Neural Networks for Geometric Graphs 背景 方法 Geom…

Kenney Assets - 提供数以万计免费商用的游戏制作素材下载,包括 2d、3d素材,游戏音效和游戏 UI

来自荷兰的游戏公司开放了自家游戏的素材包&#xff0c;制作很精美&#xff0c;下载后无需取得授权就能直接商用。 关于 Kenney Assets Kenney Assets 是游戏公司 Kenney 为游戏开发者提供的游戏素材资源网站&#xff0c;主要包括游戏 2D / 3D 人物和场景素材&#xff0c;游戏…

AXI 总线协议学习笔记(1)

引言 此文针对 XILINX的用户指南 UG761进行学习简单对AXI作说明。从下篇文章开始&#xff0c;通过阅读ARM官网的AXI协议标准进行系统学习。可以持续关注~ AXI是什么&#xff1f; AXI是ARM AMBA的一部分&#xff0c;ARM AMBA是1996年首次引入的一系列微控制器总线。 AXI的第…

ORA-29740:evicted by member %d, group incarnation %d

这个错误是在 rac 底下出现的&#xff0c;应该算是个比较严重的错误&#xff0c;就是 某个节点 被 踢&#xff08;evict&#xff09;出去了&#xff0c;导致这个节点重启系统。 这个错误的原因多种多样&#xff0c;而且需要找的日志文件也是很多的&#xff0c;基本上&#xff…

Serverless-云原生服务-概念

云原生服务是包含硬件、架构&#xff0c;硬件&#xff0c;因云而生&#xff0c;所以称为云原生技术。ServerlessFaasBaas同时具有按量付费和弹性伸缩的特点&#xff0c;该架构包括了函数维度和应用维度的两种形态关键字解析BaaS&#xff1a;Backend as a Service&#xff08;后…

termux 部署springboot 及mysql

安装应用后&#xff0c;首先在手机上运行 pkg install openssh 再运行 passwd&#xff0c;改变ssh的密码。这时在pc上用数据线连好手机&#xff0c;打开adb调试&#xff0c;将手机的端口8022映射到PC上&#xff0c;因为termux中ssh默认是8022&#xff0c;再运行一下sshd 运行…

CV-Model【8】:ConvNeXt

文章目录前言1. Abstract & Introduction1.1. Abstract1.2. Introduction2. Modernizing a ConvNet: a Roadmap2.1. Training Techniques2.2. Macro Design2.2.1. Stage ratio2.2.2. "patchif" stem2.3. ResNeXt-ify2.4. Inverted Bottleneck2.5. Large Kernel S…

AWK简单总结

目录AWK简单总结常用命令选项变量内置变量自定义变量printf命令格式AWK简单总结 awk是linux/unix下的一个强大编程工具,他支持用户自定义函数和动态正则表达式&#xff0c;灵活性强&#xff0c;运行速度快。 常用命令选项 -F fs&#xff1a;fs指定输入分隔符&#xff0c;fs可…

利用SMB协议实现局域网内设备文件的共享

文章目录参考资料说明步骤1&#xff1a;[windows]开启SMB协议步骤2&#xff1a;[windows]创建新的用户账号步骤3&#xff1a;[windows]共享文件夹属性-共享-共享属性-共享-高级共享步骤4&#xff1a;[windows]查看共享文件的主机在局域网内的IP地址步骤5&#xff1a;[ipad]打开…

华为机试题:HJ35 蛇形矩阵(python)

文章目录知识点详解1、input()&#xff1a;获取控制台&#xff08;任意形式&#xff09;的输入。输出均为字符串类型。1.1、input()与list(input())的区别、及其相互转换方法2、print() &#xff1a;打印输出。3、算术运算符4、整型int() &#xff1a;将字符串或数字转换为整型…

π122M31 双通道数字隔离器 CAN通信隔离兼容ADuM7241ARZ

π122M31 双通道数字隔离器 CAN通信隔离兼容ADuM7241ARZ电路简单、稳定性更高&#xff0c;具有出色的性能特征和可靠性&#xff0c;整体性能优于光耦和基于其他原理的数字隔离器产品。 产品传输通道间彼此独立&#xff0c;可实现多种传输方向的配置&#xff0c;可实现 5.0kVrms…

excel软件应用:如何妙用Word拆分单元格数据

打仗亲兄弟&#xff0c;上阵父子兵&#xff01;Word和Excel就是一对好兄弟&#xff0c;虽然各有分工&#xff0c;但有时也能彼此帮忙。Excel中的莫名其妙问题找Word帮忙解决&#xff0c;往往有效。譬如从平台中导出的数据&#xff0c;先使用Word做一次符号处理再粘贴到Excel中处…

Go语言基础入门第五章

string 什么是stringGo中的字符串是一个字节的切片&#xff0c;可以通过将其内容封装在""中来创建字符串&#xff0c;Go中的字符串是 Unicode 兼容的&#xff0c;并且是 UTF-8 编码。 字符串是一些字节的集合。 package mainimport "fmt"func main() {st…

白盒测试用例设计-笔记

白盒测试用例设计方法白盒设计方法静态&#xff1a;桌面检查、代码审查、代码走查、代码扫描工具动态&#xff1a;逻辑覆盖法&#xff1a;语句覆盖、判断覆盖、条件覆盖、判定条件覆盖、条件组合覆盖、路径覆盖基本路径测试法逻辑覆盖法&#xff1a;是通过对程序逻辑结构的遍历…