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

news2025/7/16 9:24:01

一、概述

策略模式的用意是针对一组算法,将每一个算法封装到具有共同接口的独立的类中,从而使得它们可以相互替换。策略模式使得算法可以在不影响到客户端的情况下发生变化

使用策略模式可以把行为和环境分割开来。环境类负责维持和查询行为类,各种算法则在具体策略类(ConcreteStrategy)中提供。由于算法和环境独立开来,算法的增减、修改都不会影响环境和客户端。当出现新的促销折扣或现有的折扣政策出现变化时,只需要实现新的策略类,并在客户端登记即可。策略模式相当于"可插入式(Pluggable)的算法"。

二、策略模式的结构

策略模式是对算法的包装,是把使用算法的责任和算法本身分割开,委派给不同的对象管理。策略模式通常把一个系列的算法包装到一系列的策略类里面,作为一个抽象策略类的子类。用一句话来说,就是:"准备一组算法,并将每一个算法封装起来,使得它们可以互换。"

策略又称做政策(Policy)模式【GOF95】。下面是一个示意性的策略模式结构图:

这个模式涉及到三个角色:

  • 环境(Context)角色:持有一个Strategy类的引用。

  • 抽象策略(Strategy)角色:这是一个抽象角色,通常由一个接口或抽象类实现。此角色给出所有的具体策略类所需的接口。

  • 具体策略(ConcreteStrategy)角色:包装了相关的算法或行为。

三、 示意性源代码

public abstract class Strategy {
    abstract public void AlgorithmInterface();
}

public class ConcreteStrategyA extends Strategy {
    // Methods
    @Override
    public void AlgorithmInterface() {
        System.out.print("Called ConcreteStrategyA.AlgorithmInterface()");
    }
}

// "ConcreteStrategyB"
public class ConcreteStrategyB extends Strategy {
    // Methods
    public void AlgorithmInterface() {
        System.out.print("Called ConcreteStrategyB.AlgorithmInterface()");
    }
}

// "ConcreteStrategyC"
public class ConcreteStrategyC extends Strategy {
    // Methods
    @Override
    public void AlgorithmInterface() {
        System.out.print("Called ConcreteStrategyC.AlgorithmInterface()");
    }
}

// "Context"
public class Context {
    // Fields
    Strategy strategy;

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

    // Methods
    public void ContextInterface() {
        strategy.AlgorithmInterface();
    }
}

/// <summary>
/// Client test
/// </summary>
public class Client {
    public static void Main(String[] args) {
        // Three contexts following different strategies
        Context c = new Context(new ConcreteStrategyA());
        c.ContextInterface();
        Context d = new Context(new ConcreteStrategyB());
        d.ContextInterface();
        Context e = new Context(new ConcreteStrategyC());
        e.ContextInterface();
    }
}

四、 何时使用何种具体策略角色

在学习策略模式时,学员常问的一个问题是:为什么不能从策略模式中看出哪一个具体策略适用于哪一种情况呢?

答案非常简单,策略模式并不负责做这个决定。换言之,应当由客户端自己决定在什么情况下使用什么具体策略角色。策略模式仅仅封装算法,提供新算法插入到已有系统中,以及老算法从系统中"退休"的方便,策略模式并不决定在何时使用何种算法。

五、 一个实际应用策略模式的例子

下面的例子利用策略模式在排序对象中封装了不同的排序算法,这样以便允许客户端动态的替换排序策略(包括Quicksort、Shellsort和Mergesort)。

abstract class SortStrategy {
    // Methods
    public abstract void Sort(List<String> list);
}

// "ConcreteStrategy"
class QuickSort extends SortStrategy {
    // Methods
    @Override
    public void Sort(List<String> list) {
        // Default is Quicksort
        System.out.print("QuickSorted list ");
    }
}

// "ConcreteStrategy"
class ShellSort extends SortStrategy {
    // Methods
    @Override
    public void Sort(List<String> list) {
        //list.ShellSort();
        System.out.print("ShellSorted list ");
    }
}

// "ConcreteStrategy"
class MergeSort extends SortStrategy {
    // Methods
    @Override
    public void Sort(List<String> list) {
        //list.MergeSort();
        System.out.print("MergeSorted list ");
    }
}

// "Context"
class SortedList {
    // Fields
    private List<String> list = new ArrayList<>();
    private SortStrategy sortstrategy;

    // Constructors
    public void SetSortStrategy(SortStrategy sortstrategy) {
        this.sortstrategy = sortstrategy;
    }

    // Methods
    public void Sort() {
        sortstrategy.Sort(list);
    }

    public void Add(String name) {
        list.add(name);
    }

    public void Display() {
        System.out.print(" name");
    }
}

/// <summary>
/// StrategyApp test
/// </summary>
public class StrategyApp {
    public static void Main(String[] args) {
        // Two contexts following different strategies
        SortedList studentRecords = new SortedList();
        studentRecords.Add("Samual");
        studentRecords.Add("Jimmy");
        studentRecords.Add("Sandra");
        studentRecords.Add("Anna");
        studentRecords.Add("Vivek");

        studentRecords.SetSortStrategy(new QuickSort());
        studentRecords.Sort();
        studentRecords.Display();
    }
}

六、 在什么情况下应当使用策略模式

在下面的情况下应当考虑使用策略模式:

1. 如果在一个系统里面有许多类,它们之间的区别仅在于它们的行为,那么使用策略模式可以动态地让一个对象在许多行为中选择一种行为。

2. 一个系统需要动态地在几种算法中选择一种。那么这些算法可以包装到一个个的具体算法类里面,而这些具体算法类都是一个抽象算法类的子类。换言之,这些具体算法类均有统一的接口,由于多态性原则,客户端可以选择使用任何一个具体算法类,并只持有一个数据类型是抽象算法类的对象。

3. 一个系统的算法使用的数据不可以让客户端知道。策略模式可以避免让客户端涉及到不必要接触到的复杂的和只与算法有关的数据。

4. 如果一个对象有很多的行为,如果不用恰当的模式,这些行为就只好使用多重的条件选择语句来实现。此时,使用策略模式,把这些行为转移到相应的具体策略类里面,就可以避免使用难以维护的多重条件选择语句,并体现面向对象设计的概念。

七、 策略模式的优点和缺点

策略模式有很多优点和缺点。它的优点有:

1. 策略模式提供了管理相关的算法族的办法。策略类的等级结构定义了一个算法或行为族。恰当使用继承可以把公共的代码移到父类里面,从而避免重复的代码。

2. 策略模式提供了可以替换继承关系的办法。继承可以处理多种算法或行为。如果不是用策略模式,那么使用算法或行为的环境类就可能会有一些子类,每一个子类提供一个不同的算法或行为。但是,这样一来算法或行为的使用者就和算法或行为本身混在一起。决定使用哪一种算法或采取哪一种行为的逻辑就和算法或行为的逻辑混合在一起,从而不可能再独立演化。继承使得动态改变算法或行为变得不可能。

3. 使用策略模式可以避免使用多重条件转移语句。多重转移语句不易维护,它把采取哪一种算法或采取哪一种行为的逻辑与算法或行为的逻辑混合在一起,统统列在一个多重转移语句里面,比使用继承的办法还要原始和落后。

策略模式的缺点有:

1. 客户端必须知道所有的策略类,并自行决定使用哪一个策略类。这就意味着客户端必须理解这些算法的区别,以便适时选择恰当的算法类。换言之,策略模式只适用于客户端知道所有的算法或行为的情况。

2. 策略模式造成很多的策略类。有时候可以通过把依赖于环境的状态保存到客户端里面,而将策略类设计成可共享的,这样策略类实例可以被不同客户端使用。换言之,可以使用享元模式来减少对象的数量。

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

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

相关文章

时序预测 | MATLAB实现LSTM-SVR(长短期记忆神经网络-支持向量机)时间序列预测

时序预测 | MATLAB实现LSTM-SVR(长短期记忆神经网络-支持向量机)时间序列预测 目录时序预测 | MATLAB实现LSTM-SVR(长短期记忆神经网络-支持向量机)时间序列预测效果一览基本介绍模型介绍LSTM模型SVR模型LSTM-SVR模型程序设计参考资料致谢效果一览 基本介绍 本次运行测试环境MA…

黑客入门(超级详细版)

据我了解&#xff0c;“黑客”大体上应该分为“正”、“邪”两类&#xff0c;正派黑客依靠自己掌握的知识帮助系统管理员找出系统中的漏洞并加以完善&#xff0c;而邪派黑客则是通过各种黑客技能对系统进行攻击、入侵或者做其他一些有害于网络的事情&#xff0c;因为邪派黑客所…

利用sim函数在m文件里运行Simulink模型

目录前言准备参考文章第一步第二步第三步前言 最近在使用Simulink做仿真的时候&#xff0c;需要在m文件里运行Simulink模型&#xff0c;用到了sim函数&#xff0c;记录一下 准备 MATLAB R2022a 参考文章 matlab函数sim,matlab sim函数究竟是怎么用的&#xff1f; Matlab中…

在SNAP中用sentinel-1数据制作DEM

在SNAP中用sentinel-1数据制作DEM0 SNAP 简介1 SNAP和snaphu的安装1.1 SNAP安装1.2 snaphu安装1.2.1 Windows系统安装snaphu1.2.2 Linux系统中安装snaphu2 基于InSAR技术制作DEM的基本原理3 数据下载&#xff0c;包括sentinel-1 SLC数据、参考DEM数据、精密轨道数据3.1 sentine…

LeetCode经典算法题:井字游戏+优势洗牌+Dota2参议院java解法

LeetCode经典算法题&#xff1a;井字游戏优势洗牌Dota2参议院java解法 井字游戏优势洗牌Dota2参议院1 井字游戏题目描述解题思路与代码2 优势洗牌题目描述解题思路与代码3 Dota2参议院题目描述解题思路与代码1 井字游戏 题目描述 用字符串数组作为井字游戏的游戏板 board&…

Linux 服务器CPU超高如何快速定位

前言 在生产环境中有时会遇见服务器CPU超高的问题&#xff0c;特别是重大版本发布后如果有内存泄露很容出现CPU超高&#xff0c;严重可能会达到100%。现在我们使用的服务器都是多核CPU&#xff0c;当出现CPU告警我们需要及时发现问题代码并处置&#xff0c;不然严重情况下会导致…

【阿旭机器学习实战】【36】糖尿病预测---决策树建模及其可视化

【阿旭机器学习实战】系列文章主要介绍机器学习的各种算法模型及其实战案例&#xff0c;欢迎点赞&#xff0c;关注共同学习交流。 【阿旭机器学习实战】【36】糖尿病预测—决策树建模及其可视化 目录【阿旭机器学习实战】【36】糖尿病预测---决策树建模及其可视化1. 导入数据并…

Datacom-HCIE考试经验分享

我是誉天Datacom秦同学。作为誉天众多通过Datacom-HCIE考试的学员之一&#xff0c;我感到很荣幸。 首先说说自学的感受吧&#xff1a; 我是从2020年开始接触网络行业的&#xff0c;听单位的前辈说华为的HCIE认证是行业含金量最高的证书&#xff0c;从那时起心里就种下了一个“I…

用 Visual Studio 升级 .NET 项目

现在&#xff0c;你已可以使用 Visual Studio 将所有 .NET 应用程序升级到最新版本的 .NET&#xff01;这一功能可以从 Visual Studio 扩展包中获取&#xff0c;它会升级你的 .NET Framework 或 .NET Core 网页和桌面应用程序。一些项目类型仍正在开发中并将在不久的未来推出&a…

spring Bean的生命周期 IOC

文章目录 1. 基础知识1.1 什么是 IoC ?2. 扩展方法3. 源码入口1. 基础知识 1.1 什么是 IoC ? IoC,控制反转,想必大家都知道,所谓的控制反转,就是把 new 对象的权利交给容器,所有的对象都被容器控制,这就叫所谓的控制反转。 IoC 很好地体现了面向对象设计法则之一 —…

适合运动时戴的蓝牙耳机有哪些、2023热门运动耳机推荐

在运动时听音乐&#xff0c;歌曲里的节奏、歌词都可以改变人的心态以及分散注意力&#xff0c;还能有效提升运动后的效果。在运动中听音乐&#xff0c;已经变为了一种随处可见的习惯。那么一款好的运动耳机&#xff0c;可以让运动更有激情&#xff0c;也能更好地享受运动的乐趣…

Pikachu靶场(暴力破解)

目录标题暴力破解&#xff08;登录&#xff09;基于表单的暴力破解验证码绕过(on server)验证码绕过(on client)token防爆破?上学期用这个靶场写过作业&#xff0c;现在抽空给它过一遍&#xff0c;由于需要抓包&#xff0c;从而通过小皮&#xff0c;使用本地&#xff08;127.0…

RestTemplate 报错 I/O error on POST request for

问题&#xff1a; org.springframework.web.client.ResourceAccessException: I/O error on POST request for "http://www.xxx.com/xxx/xxx/xxx": Read timed out; nested exception is java.net.SocketTimeoutException: Read timed out 场景&#xff1a; 在代码…

【mysql和clickhouse 查看当前链接进程信息】

前言 我们有时候服务器会突然内存溢出&#xff0c;这时候我们会去服务器上查看&#xff0c;是否是Mysql查询的时候用的时间太长&#xff0c;我们去查看当前进程情况。 正文 ClickHouse自带用于记录系统信息的系统库system&#xff0c;通过processes表&#xff0c;我们可以查…

H5项目中使用微信JS-SDK(以H5项目批量上传图片为例,兼容IOS及安卓)

H5项目中使用微信图片上传相关sdk&#xff0c;主要用于解决 1.安卓手机无法一次选择多张图片进行上传问题&#xff1b;2.控制IOS系统手机一次可无限量选择图片上传的问题 一、准备工作&#xff1a;公众号配置 验证所需使用的sdk是否符合需求 可在使用场景中&#xff0c;打开微…

MOS管选型参数:VGS(th)

MOS管选型参数&#xff1a;VGS(th) VGS&#xff08;th&#xff09;&#xff1a;开启电压&#xff08;阀值电压&#xff09;。当外加栅极控制电压 VGS 超过 VGS&#xff08;th&#xff09; 时&#xff0c;漏区和源区的表面反型层形成了连接的沟道。应用中&#xff0c;常将漏极短…

如何拥有自己的Gitee代码仓库

本教程适用码云代码托管平台 https://gitee.com/ 首先在电脑上安装Git&#xff08;哔站有安装Git教程&#xff09;和注册gitee账号后再来阅读此教程 1、在设置页面中点击 SSH公钥 2、点击 怎样生成公钥 3、点击公钥管理 4、点击 生成\添加SSH公钥 5、打开终端 输入如图红框中的…

MyBatis学习笔记(二) —— 搭建MyBatis项目

2、搭建MyBatis 2.1、开发环境 IDE&#xff1a;idea 2019.2 构建工具&#xff1a;maven 3.5.4 MySQL版本&#xff1a;MySQL 8 MyBatis版本&#xff1a;MyBatis 3.5.7 MySQL不同版本的注意事项 1、驱动类 driver-class-name MySQL 5版本使用jdbc5驱动&#xff0c;驱动类使用…

【人工智能 AI】Robotic Process Automation (RPA) 机器人流程自动化 (RPA)

目录 ROBOTIC PROCESS AUTOMATION SERVICES机器人流程自动化服务 What is RPA? 什么是机器人流程自动化?

【storybook】你需要一款能在独立环境下开发组件并生成可视化控件文档的框架吗?(三)

storybook插件addons核心插件插件APIargTypes写文档组件注释法MDX生成在线可视化UI文档上一篇&#xff1a; https://blog.csdn.net/tuzi007a/article/details/129194267插件addons 插件用于增强storybook的UI功能。 核心插件 storybook/addon-essentials 它几乎控制了整个s…