首页 > 其他分享 >策略模式:让你的代码灵活应对不同场景

策略模式:让你的代码灵活应对不同场景

时间:2023-12-22 13:32:55浏览次数:31  
标签:场景 策略 灵活 pay 代码 模式 member 算法 public


策略模式:让你的代码灵活应对不同场景_策略模式

写在前面

如果你正在为代码的可扩展性和可维护性感到烦恼,策略模式可以成为你的得力助手。本篇技术文章详细介绍了策略模式的核心原理和实战应用,帮助你解决在程序设计中所面临的挑战。无论你是初学者还是有一定经验的开发者,这篇文章都能够为你提供有益的知识和实用的技巧,值得一读!

前言

用于处理类或对象的组合的结构型的设计模式已经输出完毕:

适配器模式揭秘:让不兼容的组件完美协同

剖析装饰器模式:让你的代码更灵活、可扩展

探秘代理模式:核心原理与应用实践

优雅的程序设计:掌握门面模式的奥秘

桥梁模式:解耦抽象与实现的秘诀

组合模式揭秘:如何构建可扩展的树形结构

提升软件性能的秘密武器:揭秘实战中的享元模式

从这篇文章开始来盘一盘行为型设计模式,那么行为型的设计模式有哪些呢?行为型模式是用于描述类或对象怎样交互以及怎样分配职责,共十一种,包括策略模式、模版方法模式、观察者模式、迭代器模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。

什么是策略模式

策略模式是一种行为型设计模式,它定义了一系列算法,并将每个算法封装起来,使它们可以相互替换。策略模式的主要目的是将算法的行为和环境分开,将一系列算法封装在策略类中,并在运行时根据客户端的需求选择相应的算法。策略模式适用于需要使用多种算法,且算法之间可以相互替换的情况。在策略模式中,算法的变化不会影响到使用算法的客户端。

策略模式的核心原理

策略模式是一种行为设计模式,其核心原理是将可以相互替换的算法封装成独立的类,并使它们能够互相之间替换,以使得算法的变化独立于使用算法的客户端。

策略模式主要包括三个核心角色:

  1. Context(上下文):这个角色是策略模式中的重要组成部分,通常用于存储和传递策略对象,以及处理策略对象的交互逻辑。上下文对象在客户端的请求下,会调用合适的策略对象来执行相应的操作。
  2. Strategy(策略):这个角色通常是一个接口,用于定义各种策略对象的共同方法。具体策略对象实现这个接口,并包含具体的算法实现。策略对象不持有任何上下文对象的状态,这样保证了策略对象的可复用性。
  3. ConcreteStrategy(具体策略):这个角色是实现策略接口的具体类,包含了具体的算法实现。具体策略对象通常会持有上下文对象的状态,以便在执行算法时能够访问和修改这些状态。

策略模式:让你的代码灵活应对不同场景_设计模式_02

这三个核心角色共同实现了策略模式的核心思想:将算法与使用算法的客户端分离,使算法可以独立于客户端而变化。

策略模式如何实现

需求描述

很多购物网站都有会员业务,不同等级的会员可以享受不同程度的优惠,这里假设某会员业务系统的会员等级有非会员、初级会员、中级会员、高级会员四个等级,其中非会员在支付的时候需要全额支付 ,初级会员可以享受8折优惠,中级会员可以享受7折优惠,高级会员可以享受5折优惠,如果需要写一个支付接口,需要怎么实现呢?

实现方案

类似这样的业务模型,是比较适合使用策略模式的,但是如果仅仅使用策略模式是没有办法在主业务流程中完全避免if else的判断的,如果从实际业务出发,可以把简单工厂模式和策略模式结合起来使用。策略模式只负责定义不同的优惠策略,而简单工厂模式,负责根据不同的会员,生产出不同的具体优惠策略。具体怎么做呢?

策略模式:让你的代码灵活应对不同场景_策略模式_03

1、定义抽象的支付策略接口:PayStrategy.java;

/** * 支付策略接口 */public interface PayStrategy {
    /**
     * 实际支付金额计算
     * @param money
     */
    Double compute(Double money);
}

2、定义具体的支付策略类:Level0Streategy.java、Level1Streategy.java、Level2Streategy.java、Level3Streategy.java

/** * 非会员计费策略 */public class Level0Strategy implements PayStrategy{
    @Override
    public Double compute(Double money) {
        System.out.println("非会员开始计费");
        return money;
    }
}
/** * 初级会员计费策略 */public class Level1Strategy implements PayStrategy{
    @Override
    public Double compute(Double money) {
        System.out.println("初级会员开始计费");
        return money*0.8;
    }
}
/** * 中级会员计费策略 */public class Level2Strategy implements PayStrategy{
    @Override
    public Double compute(Double money) {
        System.out.println("中级会员开始计费");
        return money*0.7;
    }
}
/** * 高级会员计费策略 */public class Level3Strategy implements PayStrategy{
    @Override
    public Double compute(Double money) {
        System.out.println("高级会员开始计费");
        return money*0.5;
    }
}

3、定义用于存储和传递策略的上下文:StreateContext.java

/** * 支付策略上下文 */public class StrategyContent {
    private PayStrategy payStrategy;

    public StrategyContent(PayStrategy payStrategy) {
        this.payStrategy = payStrategy;
    }

    /**
     * 支付方法
     * @param money
     * @return
     */
    public Double pay(Double money){
        return this.payStrategy.compute(money);
    }
}

4、定义策略工厂类,用于生产具体的策略:PayStreategyFactory.java

/** * 策略工厂 */public class PayStrategyFactory {

    public static PayStrategy getStrategy(Member member){
        PayStrategy payStrategy;
        switch (member.getLevel()){
            case "初级":
                payStrategy=new Level1Strategy();
                break;
            case "中级":
                payStrategy=new Level2Strategy();
                break;
            case "高级":
                payStrategy=new Level3Strategy();
                break;
            default:
                payStrategy=new Level0Strategy();
                break;
        }
        return payStrategy;
    }
}

5、编写客户端:,模拟不同的用户进行支付:Test.java

@Data@AllArgsConstructorpublic class Member {    /**
     * 会员姓名
     */
    private String name;
    /**
     * 会员等级:非会员、初级、中级、高级
     */
    private String level;
    /**
     * 支付金额
     */
    private Double pay;
}
public class Test {    public static void main(String[] args) {        Member member = new Member("小明", "初级", 100.00);        PayStrategy strategy = PayStrategyFactory.getStrategy(member);
        StrategyContent strategyContent = new StrategyContent(strategy);
        Double pay = strategyContent.pay(member.getPay());
        System.out.println(member.getName() + "应支付金额:" + member.getPay() + ",实际支付金额:" + pay);
        member = new Member("小红", "中级", 100.00);
        strategy = PayStrategyFactory.getStrategy(member);
        strategyContent = new StrategyContent(strategy);
        pay = strategyContent.pay(member.getPay());
        System.out.println(member.getName() + "应支付金额:" + member.getPay() + ",实际支付金额:" + pay);
        member = new Member("铁蛋", "高级", 100.00);
        strategy = PayStrategyFactory.getStrategy(member);
        strategyContent = new StrategyContent(strategy);
        pay = strategyContent.pay(member.getPay());
        System.out.println(member.getName() + "应支付金额:" + member.getPay() + ",实际支付金额:" + pay);
        member = new Member("李2", "非会员", 100.00);
        strategy = PayStrategyFactory.getStrategy(member);
        strategyContent = new StrategyContent(strategy);
        pay = strategyContent.pay(member.getPay());
        System.out.println(member.getName() + "应支付金额:" + member.getPay() + ",实际支付金额:" + pay);
    }
}

策略模式:让你的代码灵活应对不同场景_设计模式_04

策略模式的适用场景

  1. 不同业务逻辑:在同一个业务逻辑中,可能会存在不同的策略或算法。例如,在电商网站中,可以根据不同的促销策略对商品进行不同的定价。在这种情况下,可以使用策略模式来封装不同的促销策略,并在运行时根据需要选择合适的策略。
  2. 数据排序策略:在处理大量数据时,可能需要使用不同的排序算法。例如,冒泡排序、选择排序、插入排序和二叉树排序等。在这种情况下,可以使用策略模式来定义不同的排序策略,并在运行时根据需要选择合适的策略。
  3. 算法切换:在某些情况下,可能需要根据不同的条件切换不同的算法。例如,在进行实时计算时,可能需要根据不同的输入数据选择不同的计算算法。在这种情况下,可以使用策略模式来封装不同的算法,并在运行时根据需要选择合适的算法。
  4. 行为切换:在系统中,可能需要根据不同的条件切换不同的行为。例如,在一个游戏中,可能需要根据不同的关卡选择不同的游戏策略。在这种情况下,可以使用策略模式来封装不同的游戏策略,并在运行时选择合适的行为。

总之,策略模式的应用场景非常广泛,可以用于处理不同业务逻辑、数据排序、算法切换和行为切换等方面。通过使用策略模式,我们可以将算法或行为的变化和具体实现细节分离出来,使得代码更加灵活、易于维护和扩展。

总结

优点:

  1. 避免使用多重条件语句:策略模式通过使用策略类和上下文对象来避免使用多重条件语句,如if-else语句或switch-case语句。通过将算法的行为封装到策略类中,并在运行时根据客户端的需求选择相应的算法,策略模式使得代码更加简洁、易于维护和扩展。
  2. 提供可重用的算法族:策略模式通过定义抽象策略类和具体策略类,提供了一系列的算法实现。这些算法可以在不同的上下文中重复使用,通过组合和替换不同的策略对象来满足客户端的需求。
  3. 分离算法和客户端:策略模式将算法的实现和使用分离到具体的策略类和上下文对象中。客户端只需要与上下文对象进行交互,而不需要直接处理算法的实现细节。这种分离使得代码更加清晰、易于理解和维护。
  4. 支持对开闭原则的完美支持:策略模式可以在不修改原有代码的情况下,灵活地增加新的算法。通过定义新的策略类和上下文对象,可以轻松地将新的算法集成到现有系统中,满足新的需求。
  5. 将算法的使用放到环境类中:策略模式将算法的使用放到上下文对象中,而算法的实现则移到具体策略类中。这种分离使得代码更加清晰、易于管理和扩展。
  6. 客户端必须理解所有策略算法的区别:策略模式要求客户端必须理解所有可用的策略算法的区别,以便在适当的时候选择合适的算法。这可能增加了客户端的复杂性和学习成本。

缺点

  1. 可能导致过多的策略类:策略模式可能导致创建过多的策略类,每个算法都对应一个策略类。这可能会增加系统的复杂性和维护成本。

总之,策略模式是一种行为型设计模式,它通过封装一系列可重用的算法实现,并将它们组合到不同的上下文中,实现了算法的行为和使用的分离。这种模式使得代码更加灵活、易于维护和扩展,同时支持在不修改原有代码的情况下增加新算法,从而提高了代码的灵活性和可维护性。

写在最后

感谢您阅读我们的技术文章!这篇文章详细介绍了策略模式的核心原理和实战应用,对于程序设计中所面临的问题提出了有益的解决方案。如果您觉得这篇文章有价值,请帮忙点赞和收藏,让更多人看到并受益。您的支持是我不断前行的动力和鼓励。再次感谢您的阅读和支持,期待我们的下一次相遇!

标签:场景,策略,灵活,pay,代码,模式,member,算法,public
From: https://blog.51cto.com/fanfu1024/8934539

相关文章

  • 代码写错分支怎么重新修改分支
    情景:假如有两个分支一个是开发分支:dev;一个是生产分支:main。你应该在dev分支上开发,但是不小心全都开发到main分支上了,而这些修改又不容易手动分离。解决://当前所在分支为maingitpullgitadd.gitcommit-m'注释'gitcheckoutdevgitpullgitmergemaingitpushgitche......
  • 使用代码生成工具快速开发应用-结合后端Web API提供接口和前端页面快速生成,实现通用的
    在前面随笔《在Winform应用中增加通用的业务编码规则生成》,我介绍了基于Winform和WPF的一个通用的业务编码规则的管理功能,本篇随笔介绍基于后端WebAPI接口,实现快速的Vue3+ElementPlus前端界面的开发整合,同样是基于代码生成工具实现快速的前端代码的生成处理。1、通用的业务编码......
  • 软件测试/测试开发|如何使用场景法设计测试用例?
    简介我们之前介绍过了等价类和边界值来设计我们的测试用例,等价类和边界值是我们最常用的测试用例设计方法之一,本文我们将向大家介绍场景法。场景法定义场景法是一种通过用户使用“场景”对软件系统的功能点或业务流程进行描述,即针对需求模拟出不同的场景进行所有功能点及业务流程的......
  • 阅读STM32-hal库代码得到的几点C代码编程规范
    阅读STM32-hal库代码得到的几点C代码编程规范规范一:头文件使用#ifndef_XXX_H#define_XXX_H#ifdef__cplusplusextern"C"{#endif//头文件内容#ifdef__cplusplus}#endif#endif在C++编译环境中,会定义__cplusplus宏,如果在C++代码中需要使用C语言的函数和变......
  • el-select自定义指令用于触底加载分页请求options数据(附上完整代码和接口可直接用)
    问题描述某些情况下,下拉框需要做触底加载,发请求,获取option的数据为了方便复用,笔者封装了一个自定义指令另外也提供了一个简单的接口,用于演示我们先看看效果图效果图思路分析注意事项一el-select要不嵌入到body中为何,不嵌入到body标签中呢?答曰,更加方便自定义指令管理......
  • 明晚直播:两小时玩转代码审计
    本次的课程的内容为:1.代码审计快速入门秘籍2.深入探析SQL注入白盒审计3.全流程解跑开源组件漏洞4.业务逻辑漏洞审计及防范5.漏洞发现中敏感信息泄露的重要性 12月23日晚20:00,我们不见不散~  Ms08067安全实验室专注于网络安全知识的普及和培训,是专业的“图书出版+培训”......
  • word文档转html富文本,富文本编辑器 转成html5代码
    用我现在最常使用的php框架fastadmin举例子,当然thinkphp或者原生php也是同样的原理,大家理解思路就好了、 环境:fastadmin,summernote编辑器【summernote的居中功能在段落里,且不会吃掉section标签,加上导入word功能之后,简直完美~】 按照国际惯例先放效果图  github上的de......
  • 【低代码】低代码平台协同&敏捷场景下的并行开发解决方案探索
    低代码开发平台的出现,大大地提高的产品交付效率,但是在协同开发、敏捷迭代的场景下,也暴露出了一些问题。例如:多人同时对项目进行修改,相互影响甚至修改内容被互相覆盖;同一项目下多个需求同步开发,但需求上线日期不统一,无法拆分上线等等。本文将根据不同诉求,渐进式的讨论支......
  • MyBatis-Plus 可视化代码生成器
    MyBatis-Plus可视化代码生成器来啦,让你的开发效率大大提速!!来源:blog.csdn.net/yelangkingwuzuhu/article/details/128077533前言一、mybatis-plus-generator-ui是什么?二、mybatis-plus-generator-ui怎么用?1、mavenpom引入2、新建程序入口,以main函数的方式运行3、......
  • 5分钟攻略Spring-Retry框架实现经典重试场景
    前言今天分享干货,控制了篇幅,5分钟内就能看完学会。主题是Spring-Retry框架的应用,做了一个很清晰的案例,代码可下载自测。框架介绍Spring-Retry框架是Spring自带的功能,具备间隔重试、包含异常、排除异常、控制重试频率等特点,是项目开发中很实用的一种框架。本篇所用框架的版本......