Gof23设计模式之策略模式

news2024/11/27 8:34:15

1.概述

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

2.结构

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

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

3.案例

/**
 * @author 晓风残月Lx
 * @date 2023/7/26 19:56
 *      抽象策略类
 */
public interface Strategy {

    void show();
}

/**
 * @author 晓风残月Lx
 * @date 2023/7/26 19:59
 *      具体策略类
 */
public class StrategyA implements Strategy{
    @Override
    public void show() {
        System.out.println("策略1");
    }
}


/**
 * @author 晓风残月Lx
 * @date 2023/7/26 19:59
 *      具体策略类
 */
public class StrategyB implements Strategy{
    @Override
    public void show() {
        System.out.println("策略2");
    }
}


/**
 * @author 晓风残月Lx
 * @date 2023/7/26 19:59
 *      具体策略类
 */
public class StrategyC implements Strategy{
    @Override
    public void show() {
        System.out.println("策略3");
    }
}


/**
 * @author 晓风残月Lx
 * @date 2023/7/26 20:00
 *      促销员(环境类)
 */
public class SalesMan {

    // 聚合策略类对象
    private Strategy strategy;

    public Strategy getStrategy() {
        return strategy;
    }

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

    public SalesMan(Strategy strategy) {
        this.strategy = strategy;
    }

    // 由促销员展示促销活动给用户
    public void salesManShow() {
        strategy.show();
    }

}

/**
 * @author 晓风残月Lx
 * @date 2023/7/26 20:02
 */
public class Client {

    public static void main(String[] args) {

        SalesMan salesMan = new SalesMan(new StrategyA());
        salesMan.salesManShow();


        salesMan.setStrategy(new StrategyC());
        salesMan.salesManShow();

    }
}

在这里插入图片描述

4.优缺点

1,优点:

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

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

  • 易于扩展

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

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

2,缺点:

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

5.使用场景

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

6.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方法可以传一个新策略让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/978224.html

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

相关文章

剑指 Offer 43. 1~n 整数中 1 出现的次数(困难)

题目&#xff1a; class Solution { public:int countDigitOne(int n) {// mulk 表示 10^k// 在下面的代码中&#xff0c;可以发现 k 并没有被直接使用到&#xff08;都是使用 10^k&#xff09;// 但为了让代码看起来更加直观&#xff0c;这里保留了 klong long mulk 1;int…

Text Workflow for Mac,简单易用的文本转换工具

如果你需要一个能够将文本转换成多种语言和文件格式的工具&#xff0c;那么Text Workflow for Mac将是你的不二之选。 这个软件支持多种语言翻译和多种文件格式转换&#xff0c;让你可以轻松地将文本转换成你需要的形式。而且&#xff0c;它的操作非常简单&#xff0c;只需要几…

精讲算法的时间复杂度

目录 一、算法效率 1.算法效率 1.1如何衡量一个算法的好坏 1.2算法的复杂度 二、时间复杂度 1.时间复杂度的概念 2.大O的渐进表示法 3.常见时间复杂度的计算举例 三、空间复杂度 一、算法效率 1.算法效率 1.1如何衡量一个算法的好坏 long long Fib(int N) {if(N <…

Day6:浅谈useState

「目标」: 持续输出&#xff01;每日分享关于web前端常见知识、面试题、性能优化、新技术等方面的内容。 Day6-今日话题 谈谈react hooks中的useState &#xff0c;将从以下七个角度介绍&#xff1a; 用法 参数 返回值 作用 工作原理 优缺点 注意点 用法 useState 是一个函数&a…

Hugging News #0904: 登陆 AWS Marketplace

每一周&#xff0c;我们的同事都会向社区的成员们发布一些关于 Hugging Face 相关的更新&#xff0c;包括我们的产品和平台更新、社区活动、学习资源和内容更新、开源库和模型更新等&#xff0c;我们将其称之为「Hugging News」。本期 Hugging News 有哪些有趣的消息&#xff0…

VMware虚拟机安装CentOS7设置静态ip

vim /etc/sysconfig/network-scripts/ifcfg-ens33修改BOOTPROTO的值为static 增加最后那四项&#xff0c;参数在编辑&#xff0c;虚拟网络编辑器里面看

合宙Air724UG LuatOS-Air LVGL API控件-滑动条 (Slider)

滑动条 (Slider) 滑动条看起来和进度条是有些是有些像&#xff0c;但不同的是滑动条可以进行数值选择。 示例代码 -- 回调函数 slider_event_cb function(obj, event)if event lvgl.EVENT_VALUE_CHANGED then local val (lvgl.slider_get_value(obj) or "0")..&…

手写bind方法

<script>/** 手写bind方法* */Function.prototype.myBind function (thisArg, ...args) {return (...newArgs) > {return this.call(thisArg, ...args, ...newArgs)}}const obj {name: zs,age: 18,}function fn (a, b, c) {console.log(this)console.log(a b c)re…

《数据出境安全评估办法》解读

一、数据出境的统一评估体系正式确立 自我国《网络安全法》规定了关键信息基础设施运营者的重要数据与个人信息出境评估制度后&#xff0c;至今历时五年&#xff0c;关于数据出境及个人信息出境安全评估的立法体例、评估机制一直在探索过程中。 其后&#xff0c;国家互联网信…

PYTHON知识点学习-字典

&#x1f308;write in front&#x1f308; &#x1f9f8;大家好&#xff0c;我是Aileen&#x1f9f8;.希望你看完之后&#xff0c;能对你有所帮助&#xff0c;不足请指正&#xff01;共同学习交流. &#x1f194;本文由 Aileen_0v0&#x1f9f8; 原创 CSDN首发&#x1f412; 如…

java IO流(三) 转换流 打印流

转换流 前面我们学习过FileReader读取文件中的字符&#xff0c;但是FileReader默认只能读取UTF-8编码格式的文件。如果使用FileReader读取GBK格式的文件&#xff0c;可能存在乱码&#xff0c;因为FileReader遇到汉字默认是按照3个字节来读取的&#xff0c;而GBK格式的文件一个…

如何写一个sh脚本将一个本地文件通过 scp命令上传到远程的 centos服务器?

如何写一个sh脚本将一个本地文件通过 scp命令上传到远程的 centos服务器&#xff1f; 1.1 背景需求1.2 解决方案1.3 附录1.3.1 scp命令用法与示例1.3.1.1 scp命令用法与解释1.3.1.2 scp 命令用法示例1.3.1.2.1 示例一&#xff1a;从本地复制文件到远程计算机1.3.1.2.2 示例二&a…

Sqlserver 在 SELECT 语句中显示来自 GROUP BY 子句中未涉及的列

在SQL Server中&#xff0c;如果您在GROUP BY子句中对某些列进行了分组&#xff0c;但想在SELECT语句中同时显示未涉及到的其他列&#xff0c;您可以使用聚合函数和子查询的方法来实现。这可以通过在GROUP BY子查询中获取需要的聚合值&#xff0c;并在外部查询中选择其他列来完…

Java复习-20-接口(3)- 代理设计模式

代理设计模式(Proxy) 功能&#xff1a;可以帮助用户将所有的开发注意力只集中在核心业务功能的处理上。 代理模式(Proxy Pattern)是一种结构性模式。代理模式为一个对象提供了一个替身&#xff0c;以控制对这个对象的访问。即通过代理对象访问目标目标对象&#xff0c;可以在目…

复旦-华盛顿EMBA:走近亿咖通科技,探寻汽车智能化的科创“密码”

6月20日&#xff0c;应复旦大学-华盛顿大学EMBA项目18班校友周靖的邀请&#xff0c;项目校友参访了科创企业ECARX亿咖通科技。作为该公司资深副总裁、中国首席财务官&#xff0c;周靖带领大家通过产品演示、实车驾驶和交流对话探寻汽车智能化的科创“密码”&#xff0c;近距离感…

1.初识爬虫

爬虫是批量模拟网络请求的程序&#xff0c;想百度谷歌这种搜索类网站本质上就是爬虫 使用爬虫的时候不应该对别人的网站有严重的影响&#xff0c;比如你爬的频率太高了&#xff0c;让人家的网站崩溃了。不应该爬取网页上显示不到的内容&#xff0c;比如有一个直播的网站&#…

【SLAM】G2O优化库超详细解析

G2O&#xff0c;与ceres并列为目前视觉SLAM中应用最广泛的优化算法库。它最大的特点就是基于图优化设计&#xff0c;这对于视觉SLAM来说是异常适配的。在很多的SLAM库的中都使用到它来进行优化操作&#xff0c;比如ORB-SLAM。 代码仓库&#xff1a;https://github.com/RainerK…

渗透测试漏洞原理之---【不安全的反序列化】

文章目录 1、序列化与反序列化1.1、引入1.2、序列化实例1.2.1、定义一个类1.2.2、创建 对象1.2.3、反序列化1.2.4、对象注入 2、漏洞何在2.1、漏洞触发2.1.2、定义一个类2.1.3、定义一个对象2.1.3、反序列化执行代码 2.2 为什么会这样 3、反序列化漏洞攻防3.1、PHP反序列化实例…

[杂谈]-快速了解LoRaWAN网络以及工作原理

快速了解LoRaWAN网络以及工作原理 文章目录 快速了解LoRaWAN网络以及工作原理1、LoRaWAN网络元素1.1 终端设备&#xff08;End Devices&#xff09;1.2 网关&#xff08;Gateways&#xff09;1.3 网络服务器&#xff08;Net Server&#xff09;1.4 应用服务器&#xff08;Appli…

计算机网络的故事——确认访问用户身份的认证

确认访问用户身份的认证 HTTP使用的认证方式&#xff1a;BASIC认证&#xff08;基本认证&#xff09;、DIGEST&#xff08;摘要认证&#xff09;、SSL客户端认证、FormBase认证&#xff08;基于表单认证&#xff09;。 基于表单的认证&#xff1a;涉及到session管理以及cookie…