策略模式的实现与应用:掌握灵活算法切换的技巧

news2024/11/25 2:29:32

文章目录

  • 常用的设计模式有以下几种:
    • 一.创建型模式(Creational Patterns):
    • 二.结构型模式(Structural Patterns):
    • 三.行为型模式(Behavioral Patterns):
    • 四.并发模式(Concurrent Patterns):
  • 策略模式概念
  • 一、策略模式例子一
  • 二、策略模式例子二
  • 三、策略模式例子三
  • 总结


常用的设计模式有以下几种:

**

一.创建型模式(Creational Patterns):

工厂模式(Factory Pattern)
抽象工厂模式(Abstract Factory Pattern)
单例模式(Singleton Pattern)
原型模式(Prototype Pattern)
建造者模式(Builder Pattern)

二.结构型模式(Structural Patterns):

适配器模式(Adapter Pattern)
桥接模式(Bridge Pattern)
装饰器模式(Decorator Pattern)
组合模式(Composite Pattern)
外观模式(Facade Pattern)
享元模式(Flyweight Pattern)
代理模式(Proxy Pattern)

三.行为型模式(Behavioral Patterns):

策略模式(Strategy Pattern)
观察者模式(Observer Pattern)
迭代器模式(Iterator Pattern)
命令模式(Command Pattern)
模板方法模式(Template Method Pattern)
职责链模式(Chain of Responsibility Pattern)
状态模式(State Pattern)
访问者模式(Visitor Pattern)
中介者模式(Mediator Pattern)
备忘录模式(Memento Pattern)
解释器模式(Interpreter Pattern)

四.并发模式(Concurrent Patterns):

单例模式(Singleton Pattern,在多线程环境下的应用)
生成器模式(Builder Pattern,在多线程环境下的应用)
保护性暂停模式(Guarded Suspension Pattern)
观察者模式(Observer Pattern,在多线程环境下的应用)

这些设计模式涵盖了对象的创建、对象间的组织和交互、以及对象的行为等方面,可以帮助开发者更好地组织和设计代码,提高代码的可扩展性、可维护性以及重用性。需要根据实际情况选择适合的设计模式来解决问题。**


策略模式概念

今天来讲一讲策略模式:
策略模式(Strategy Pattern)是一种行为设计模式,它允许你定义一系列算法,并将每个算法封装到独立的类中,使它们可以互相替换。策略模式使得算法的变化独立于使用它们的客户端。
在策略模式中,有一个上下文(Context)对象,它持有一个策略接口的引用,并通过调用策略接口的方法来执行具体的算法。算法类实现了策略接口,每个算法类都封装了一种具体的算法,客户端可以根据需要选择不同的策略对象,从而实现不同的行为。🤩🤩🤩
策略模式的优点包括:

1. 算法可以灵活地替换或新增,不影响使用算法的客户端。
2. 可以消除大量的条件语句,提高代码的可维护性和可读性。
3. 可以将算法的实现细节封装起来,提高代码的模块性和复用性。

策略模式在许多场景下都有应用,比如排序算法、计算费用、验证用户等。通过使用策略模式,可以优雅地处理复杂的逻辑,并提供一种可扩展、易于维护的解决方案。🤗🤗🤗

我并不喜欢看含义,对于这种概念性的东西,动手实践才是硬道理!
以下举出 策略模式 的几个 荔枝!!!😍😍😍
相信看完会更加理解策略模式的强大性!

在这里插入图片描述

一、策略模式例子一

假设我们正在开发一个商场收银系统,其中有不同的折扣策略供用户选择,包括无折扣、固定折扣和打折折扣。我们希望通过策略模式来实现这些不同的折扣策略。
首先,我们定义一个抽象的策略接口 DiscountStrategy,它声明了一个计算折扣金额的方法 calculateDiscount:

public interface DiscountStrategy {
    double calculateDiscount(double amount);
}

然后,我们分别实现三种具体的策略类:NoDiscountStrategy(无折扣)、FixedDiscountStrategy(固定折扣)和PercentageDiscountStrategy(打折折扣)。它们都实现了 DiscountStrategy 接口:

public class NoDiscountStrategy implements DiscountStrategy {
    @Override
    public double calculateDiscount(double amount) {
        return 0; // 无折扣,返回0
    }
}

public class FixedDiscountStrategy implements DiscountStrategy {
    private double discount;

    public FixedDiscountStrategy(double discount) {
        this.discount = discount;
    }

    @Override
    public double calculateDiscount(double amount) {
        return discount; // 固定折扣,直接返回固定的折扣金额
    }
}

public class PercentageDiscountStrategy implements DiscountStrategy {
    private double percentage;

    public PercentageDiscountStrategy(double percentage) {
        this.percentage = percentage;
    }

    @Override
    public double calculateDiscount(double amount) {
        return amount * percentage; // 打折折扣,根据折扣比例计算折扣金额
    }
}

最后,我们定义一个上下文类 Cashier,它持有一个 DiscountStrategy 的引用,并在结算时调用该策略的方法:

public class Cashier {
    private DiscountStrategy discountStrategy;

    public void setDiscountStrategy(DiscountStrategy discountStrategy) {
        this.discountStrategy = discountStrategy;
    }

    public double calculateTotalWithDiscount(double amount) {
        double discount = discountStrategy.calculateDiscount(amount);
        return amount - discount;
    }
}

现在,我们可以使用策略模式来实现商场收银系统的折扣功能了。示例如下:

public class Main {
    public static void main(String[] args) {
        Cashier cashier = new Cashier();

        // 设置无折扣策略
        DiscountStrategy noDiscountStrategy = new NoDiscountStrategy();
        cashier.setDiscountStrategy(noDiscountStrategy);
        double total = cashier.calculateTotalWithDiscount(100);
        System.out.println("Total with no discount: " + total);

        // 设置固定折扣策略
        DiscountStrategy fixedDiscountStrategy = new FixedDiscountStrategy(20);
        cashier.setDiscountStrategy(fixedDiscountStrategy);
        total = cashier.calculateTotalWithDiscount(100);
        System.out.println("Total with fixed discount: " + total);

        // 设置打折折扣策略
        DiscountStrategy percentageDiscountStrategy = new PercentageDiscountStrategy(0.1);
        cashier.setDiscountStrategy(percentageDiscountStrategy);
        total = cashier.calculateTotalWithDiscount(100);
        System.out.println("Total with percentage discount: " + total);
    }
}

输出结果:

Total with no discount: 100.0
Total with fixed discount: 80.0
Total with percentage discount: 90.0

通过策略模式,我们可以灵活地选择不同的折扣策略,并在运行时动态地切换和应用这些策略,而不需要修改 Cashier 类的代码。这样,我们可以方便地添加新的折扣策略或修改现有策略的实现,而不会对其他部分产生影响。这样的设计符合开闭原则,增加了代码的可维护性和扩展性。

二、策略模式例子二

例子2:排序算法
假设我们正在设计一个排序工具,它可以根据用户选择的不同排序算法对数据进行排序。我们可以使用策略模式来实现不同的排序策略。
首先,我们定义一个排序策略接口 SortingStrategy,它声明了一个排序方法 sort:

public interface SortingStrategy {
    void sort(int[] array);
}

然后,我们分别实现两种具体的策略类:BubbleSortStrategy(冒泡排序)和 QuickSortStrategy(快速排序)。它们都实现了 SortingStrategy 接口:

public class BubbleSortStrategy implements SortingStrategy {
    @Override
    public void sort(int[] array) {
        // 冒泡排序算法的具体实现
        // ...
    }
}

public class QuickSortStrategy implements SortingStrategy {
    @Override
    public void sort(int[] array) {
        // 快速排序算法的具体实现
        // ...
    }
}

最后,我们定义一个上下文类 Sorter,它持有一个 SortingStrategy 的引用,并在排序时调用该策略的方法:

public class Sorter {
    private SortingStrategy sortingStrategy;

    public void setSortingStrategy(SortingStrategy sortingStrategy) {
        this.sortingStrategy = sortingStrategy;
    }

    public void sortArray(int[] array) {
        sortingStrategy.sort(array);
    }
}

现在,我们可以使用策略模式来实现排序工具了。示例如下:

public class Main {
    public static void main(String[] args) {
        Sorter sorter = new Sorter();

        // 使用冒泡排序策略
        SortingStrategy bubbleSortStrategy = new BubbleSortStrategy();
        sorter.setSortingStrategy(bubbleSortStrategy);
        int[] array = {5, 3, 8, 2, 1};
        sorter.sortArray(array);
        System.out.println("Sorted array using bubble sort:");
        for (int num : array) {
            System.out.print(num + " ");
        }
        System.out.println();

        // 使用快速排序策略
        SortingStrategy quickSortStrategy = new QuickSortStrategy();
        sorter.setSortingStrategy(quickSortStrategy);
        int[] array2 = {9, 4, 6, 2, 7};
        sorter.sortArray(array2);
        System.out.println("Sorted array using quick sort:");
        for (int num : array2) {
            System.out.print(num + " ");
        }
        System.out.println();
    }
}

输出结果:

Sorted array using bubble sort:
1 2 3 5 8 
Sorted array using quick sort:
2 4 6 7 9

通过策略模式,我们可以灵活地选择不同的排序策略,而不需要修改 Sorter 类的代码。这样,我们可以方便地添加新的排序策略或修改现有策略的实现,而不会对其他部分产生影响。

三、策略模式例子三

假设我们正在开发一个电商平台,针对不同的用户类型(普通用户、VIP用户、管理员),我们需要为其提供不同的登录方式。
首先,我们定义一个登录策略接口 LoginStrategy,它声明了一个登录方法 login:

public interface LoginStrategy {
    void login();
}

然后,我们分别实现三种具体的策略类:DefaultLoginStrategy(普通用户登录方式)、VIPLoginStrategy(VIP用户登录方式)和 AdminLoginStrategy(管理员登录方式)。它们都实现了 LoginStrategy 接口:

public class DefaultLoginStrategy implements LoginStrategy {
    @Override
    public void login() {
        System.out.println("使用用户名和密码登录");
        // 具体的登录逻辑
    }
}

public class VIPLoginStrategy implements LoginStrategy {
    @Override
    public void login() {
        System.out.println("使用手机号和密码登录");
        // 具体的登录逻辑
    }
}

public class AdminLoginStrategy implements LoginStrategy {
    @Override
    public void login() {
        System.out.println("使用管理员账号和密码登录");
        // 具体的登录逻辑
    }
}

最后,我们定义一个上下文类 LoginContext,它持有一个 LoginStrategy 的引用,并在登录时调用该策略的方法:

public class LoginContext {
    private LoginStrategy loginStrategy;

    public void setLoginStrategy(LoginStrategy loginStrategy) {
        this.loginStrategy = loginStrategy;
    }

    public void performLogin() {
        loginStrategy.login();
    }
}

现在,我们可以使用策略模式来为不同的用户类型提供不同的登录方式了。示例如下:

public class Main {
    public static void main(String[] args) {
        LoginContext loginContext = new LoginContext();

        // 普通用户登录
        LoginStrategy defaultLoginStrategy = new DefaultLoginStrategy();
        loginContext.setLoginStrategy(defaultLoginStrategy);
        loginContext.performLogin();

        // VIP用户登录
        LoginStrategy vipLoginStrategy = new VIPLoginStrategy();
        loginContext.setLoginStrategy(vipLoginStrategy);
        loginContext.performLogin();

总结

UU们,懂了嘛!!!😄😄😄
不懂可以评论区留言,俺可以再举更多的 荔枝~~~

@作者:加辣椒了吗?
简介:憨批大学生一枚,喜欢在博客上记录自己的学习心得,也希望能够帮助到你们!
在这里插入图片描述

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

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

相关文章

【RabbitMQ(day1)】RabbitMQ的概述和安装

入门RabbitMQ 一、RabbitMQ的概述二、RabbitMQ的安装三、RabbitMQ管理命令行四、RabbitMQ的GUI界面 一、RabbitMQ的概述 MQ(Message Queue)翻译为消息队列,通过典型的【生产者】和【消费者】模型,生产者不断向消息队列中生产消息&…

macOS Ventura 13.5 (22G74) Boot ISO 原版可引导镜像下载

macOS Ventura 13.5 (22G74) Boot ISO 原版可引导镜像下载 本站下载的 macOS 软件包,既可以拖拽到 Applications(应用程序)下直接安装,也可以制作启动 U 盘安装,或者在虚拟机中启动安装。另外也支持在 Windows 和 Lin…

css终极方案PostCSS

一见如故 原理 所有的css框架都在一样的事,那就是由一个css生成一个新的css,那么postcss就来做了一个抽离: 1、将原有的css解析成抽象语法树 2、中间经过若干个插件 3、重新文本化,形成新的css postcss.config.js module.expor…

MX Linux 23 RC1发布

导读MX Linux的开发者宣布MX Linux 23的第一个候选版本已经发布。 MX Linux 是基于 Debian 稳定分支的面向桌面的 Linux 发行,它是 antiX 及早先的 MEPIS Linux 社区合作的产物。它采用 Xfce 作为默认桌面环境,是一份中量级操作系统,并被设计…

技术速览|Meta Llama 2 下一代开源大型语言模型

AI 使用大型语言模型(LLM)来理解和生成自然语言。LLM 可以从大量文本中学习并创建有关各种主题的文本,并可以完成比如编写代码、生成歌词、总结文章等任务。但有些 LLM 相关课程成本高昂且封闭,而现有的开放课程数量十分有限。这就…

游戏引擎UE如何革新影视行业?创意云全面支持UE云渲染

虚幻引擎UE(Unreal Engine)作为一款“殿堂级”的游戏引擎,占据了全球80%的商用游戏引擎市场,但如果仅仅将其当做游戏开发的工具,显然是低估了它的能力。比如迪士尼出品的电视剧《曼达洛人》、电影《狮子王》等等都使用…

Server - 调用 K8S 集群 GPU 环境运行算法脚本

欢迎关注我的CSDN:https://spike.blog.csdn.net/ 本文地址:https://blog.csdn.net/caroline_wendy/article/details/131899662 Kubeflow 是基于 Kubernetes 的机器学习工具包,提供了一套技术栈,包含了很多组件,用于支持…

魔功心法-枚举篇

什么是枚举 枚:量词。一般用于较小的片状物,相当于“个”。 举:提出:列举。举一反三。举个例子。 所以,枚举就是一个个列举出来 枚举的作用 魔功的作用,就不过多描述了,主打的就是一个优雅。…

将AWS S3大文件文件上传相关的API集成为js文件,功能包括 多文件并行上传、文件分片上传、断点续传、文件分片合成、上传暂停、取消上传、文件上传进度条显示

地址 https://github.com/gk-1213/easy-s3/tree/main easy-s3 将AWS S3大文件文件上传相关的API集成为js文件,功能包括多文件并行上传、文件分片上传、断点续传、文件分片合成、上传暂停、取消上传、文件上传进度条显示。 暂时不包括文件分片下载相关功能&#…

网工实操基础学习23.07.05

1.交换机,路由器 交换机的作用是链接同一个网络下的所有设备,如果有无线设备加入,需要添加AP(无线接入点)设备在交换机层次上 路由器的作用是将不同网络下的设备链接 2.IP地址 划分网段:网络位、网段、…

C++第三方开发库matplotlib-cpp

Matplotlib-cpp是一个用于在C中绘制图表的开源库。它提供了与Python的Matplotlib库类似的功能,使得在C环境下进行数据可视化变得更加便捷。基于Matplotlib-cpp,我们可以使用各种绘图函数和样式选项来创建各种类型的图表,包括折线图、散点图、…

单片机第一季:零基础11——实时时钟DS1302

目录 1,DS1302 时钟芯片介绍 2,BCD码介绍 3,涉及到的寄存器 3.1,控制寄存器 3.2,日历/时钟寄存器 3.3,DS1302 的读写时序 4,相关代码 这一章我们来学习DS1302 时钟芯片&#xff0c…

数据结构栈和队列

3.栈和队列 3.1栈和队列的定义和特点 栈和队列是两种常用的、重要的数据结构栈和队列是限定插入和删除只能在表的 “ 端点 ”进行的线性表栈和队列是线性表的子集(是插入和删除位置受限的线性表) 栈的应用: ​ 由于栈的操作具有后进先出的…

国内疫情地图和省级疫情地图

基础地图演示 from pyecharts.charts import Mapfrom pyecharts.options import VisualMapOpts map Map() data [ ("北京", 99), ("上海", 199), ("湖南", 299), ("台湾", 199), ("安徽", 299), ("广州", 399…

干货满满-运营校园跑腿小程序

校园跑腿是指在校园内提供代办、送餐、购物等服务的一种形式。学生可以通过跑腿服务解决一些日常生活中的繁琐事务,节省时间和精力。在校园跑腿小程序运营中,你可以尝试以下方法进行运营管理: (1)注册或加入相关的校园…

fdbus和proto编译

1. 下载protobuf和FDBUS 1.下载 FDBUS需要用到protobuf,所以需要提前安装好protobuf。 protobuf下载地址 https://gitee.com/it-monkey/protocolbuffers/ fdbus下载地址 https://gitee.com/jeremyczhen/fdbus 2. Windows编译 生成vs工程 打开CMake&#xff…

(vue)vue项目中引入外部字体

(vue)vue项目中引入外部字体 效果: 第一步 放置字体包,在assets下创建一个fonts文件夹,放入下载的字体文件 第二步 创建一个font.css文件用于定义这个字体包的名字 第三步 在App.vue的css中将这个css文件引入 第四步 页面使用 font-famil…

NumPy 专业人士应该掌握的 45 个技能

一、说明 NumPy(或Numeric Python)是每个数据科学和机器学习项目的核心。 整个数据驱动的生态系统在某种程度上依赖于NumPy及其核心功能。这使它成为 Python 有史以来最重要和改变游戏规则的库之一。 鉴于NumPy由于其无与伦比的潜力而在工业界和学术界具…

java文件相关操作工具,包括读取服务器路径下文件,删除文件及子文件,删除文件夹等方法

文章目录 一、记录文件相关操作方法二、代码1.读取路径返回List\<File>2.读取路径返回List\<String>3.删除文件夹4.删除文件 一、记录文件相关操作方法 二、代码 1.读取路径返回List<File> import org.slf4j.LoggerFactory; import org.slf4j.Logger;impo…

【学会动态规划】按摩师(11)

目录 动态规划怎么学&#xff1f; 1. 题目解析 2. 算法原理 1. 状态表示 2. 状态转移方程 3. 初始化 4. 填表顺序 5. 返回值 3. 代码编写 写在最后&#xff1a; 动态规划怎么学&#xff1f; 学习一个算法没有捷径&#xff0c;更何况是学习动态规划&#xff0c; 跟我…