策略(政策)模式

ops/2024/10/15 11:16:21/

简介

策略模式(Strategy Pattern)又叫作政策模式(Policy Pattern),它将定义的算法家族分别封装起来,让它们之间可以互相替换,从而让算法的变化不会影响到使用算法的用户,属于行为型设计模式。

通用模板

  1. 创建抽象策略角色:规定策略或算法的行为。

    // 策略接口
    public interface IStrategy {void algorithm();
    }
    
  2. 创建具体策略角色:具体的策略或算法实现。

    // 具体策略类A
    public class ConcreteStrategyA implements IStrategy{@Overridepublic void algorithm() {System.out.println("ConcreteStrategyA");}
    }
    
    // 具体策略类B
    public class ConcreteStrategyB implements IStrategy {@Overridepublic void algorithm() {System.out.println("ConcreteStrategyB");}
    }
    
  3. 上下文角色:用来操作策略的上下文环境,屏蔽高层模块(客户端)对策略、算法的直接访问,封装可能存在的变化。

    // 操作策略的上下文
    public class Context {private IStrategy strategy;public Context(IStrategy strategy) {this.strategy = strategy;}public void algorithm() {this.strategy.algorithm();}
    }
    

模板测试

  1. 测试代码

    public class Client {public static void main(String[] args) {// 选择一个具体策略IStrategy strategy = new ConcreteStrategyA();// 创建一个上下文环境Context context = new Context(strategy);// 客户端直接让上下文角色执行算法context.algorithm();}
    }
    
  2. 结果

    ConcreteStrategyA
    

应用场景

策略模式在生活场景中的应用非常多。比如,一个人的纳税比率与他的工资有关,不同的工资水平对应不同的税率。再比如,在互联网移动支付的大背景下,我们每次下单后付款前,都需要选择支付方式。

策略模式可以解决在有多种相似算法的情况下使用if…else或switch…case所带来的复杂性和臃肿性问题。在日常业务开发中,策略模式适用于以下应用场景。
(1)针对同一类型问题,有多种处理方式,每一种都能独立解决问题。
(2)需要自由切换算法的场景。
(3)需要屏蔽算法规则的场景。

优点

(1)策略模式符合开闭原则。
(2)避免使用多重条件转移语句,如if…else语句、switch…case语句
(3)使用策略模式可以提高算法的保密性和安全性。

缺点

(1)客户端必须知道所有的策略,并且自行决定使用哪一个策略类。
(2)代码中会产生非常多策略类,增加维护难度。

“生搬硬套”实战

场景描述

假设你是一名餐厅经理,餐厅提供多种优惠活动来吸引顾客。优惠活动包括打折、满减、买一送一等。每种优惠活动都有不同的计算方式,但餐厅的收银系统需要能够灵活地应用这些优惠活动。

代码开发
  1. 创建抽象策略角色(这里指打折策略接口)

    // 打折策略接口
    public interface IDiscountStrategy {double applyDiscount(double originalPrice);
    }
    
  2. 创建具体策略角色(这里指百分比打折策略、固定金额减免策略、买一送一策略)

    // 根据折扣百分比计算最终价格
    public class PercentageDiscount implements IDiscountStrategy {private double discountPercentage;public PercentageDiscount(double discountPercentage) {this.discountPercentage = discountPercentage;}@Overridepublic double applyDiscount(double originalPrice) {return originalPrice * (1 - discountPercentage / 100);}
    }
    
    // 根据固定金额减免计算最终价格
    public class FixedAmountDiscount implements IDiscountStrategy {private double discountAmount;public FixedAmountDiscount(double discountAmount) {this.discountAmount = discountAmount;}@Overridepublic double applyDiscount(double originalPrice) {return Math.max(originalPrice - discountAmount, 0); // 确保折扣后价格不低于0}
    }
    
    // 买一送一策略,计算最终价格为原价的一半
    public class BuyOneGetOneFree implements IDiscountStrategy {@Overridepublic double applyDiscount(double originalPrice) {return originalPrice / 2; // 买一送一,相当于半价}
    }
    
  3. 创建上下文(这里就是收银系统)

    // 用来操作策略的上下文,这里就是收银系统
    public class Cashier {private IDiscountStrategy strategy;public Cashier(IDiscountStrategy strategy) {this.strategy = strategy;}public double calculateFinalPrice(double originalPrice) {return strategy.applyDiscount(originalPrice);}
    }
    

至此,我们就通过“生搬硬套”策略模式的模板设计出一套上下文可以灵活选择不同策略算法的系统,接下来我们进行测试:

  • 测试代码
    public class Client {public static void main(String[] args) {// 折扣百分比策略IDiscountStrategy percentageDiscount = new PercentageDiscount(10);Cashier cashierWithPercentageDiscount = new Cashier(percentageDiscount);double finalPriceWithPercentage = cashierWithPercentageDiscount.calculateFinalPrice(100);System.out.println("Final price with percentage discount: " + finalPriceWithPercentage);// 固定金额减免策略IDiscountStrategy fixedAmountDiscount = new FixedAmountDiscount(20);Cashier cashierWithFixedAmountDiscount = new Cashier(fixedAmountDiscount);double finalPriceWithFixedAmount = cashierWithFixedAmountDiscount.calculateFinalPrice(100);System.out.println("Final price with fixed amount discount: " + finalPriceWithFixedAmount);// 买一送一策略IDiscountStrategy buyOneGetOneFree = new BuyOneGetOneFree();Cashier cashierWithBuyOneGetOneFree = new Cashier(buyOneGetOneFree);double finalPriceWithBuyOneGetOneFree = cashierWithBuyOneGetOneFree.calculateFinalPrice(100);System.out.println("Final price with buy one get one free: " + finalPriceWithBuyOneGetOneFree);}
    }
    
  1. 结果
    Final price with percentage discount: 90.0
    Final price with fixed amount discount: 80.0
    Final price with buy one get one free: 50.0
    

总结

策略是指,定义一组算法,并把其封装到一个对象中。然后在运行时,可以灵活的使用其中的一个算法。这种模式非常适合那些需要根据不同情况选择不同行为的场景。


http://www.ppmy.cn/ops/119109.html

相关文章

vue 流式加载mp4文件

video组件 传入assetURL视频地址即可&#xff0c;组件内配置了代理&#xff0c;注意配置/video-api 代理 <template><video ended"emits(ended)" autoplay muted ref"video"><source type"video/mp4" />Your browser does no…

腾讯邮箱上传附件卡、慢、无法上传,下载慢问题处理

1、检查文件中转站容量是否已满 2、建议用户打开链接https://exmail.qq.com/qy_mng_logic/wasmHelper?typehashv2&#xff0c;看是否可以正常访问。&#xff08;能打开下载就表示可以正常访问&#xff09; 3、让用户切换到4G或者其他网络再重新上传附件是否会重现问题&#xf…

【WSL——Windows 上使用 Linux 环境】

引入 以前在windows上使用linux工具链&#xff0c;一般都要安装虚拟机&#xff08;VMware/virtualBox)。虚拟机的缺点是&#xff0c;因为是完整的虚拟环境&#xff0c;消耗系统资源比较多。 windows自己开发了WSL功能&#xff0c;实现了虚拟机的功能&#xff0c;但是比虚拟机性…

goland使用redis实现签到功能

签到封装&#xff1a;直接调用即可&#xff0c;基本满足所有签到操作 package mainimport ("context""fmt""time""github.com/go-redis/redis/v8" )type UserSign struct {rdb *redis.Client }func NewUserSign(opt *redis.Options) …

Linux云计算 |【第四阶段】PROJECT2-DAY1

综合项目内容&#xff1a; 部署数据库服务MySQL、部署共享存储NFS、配置网站服务、测试配置 一、项目拓扑结构 PROJECT1回顾&#xff1a; PROJECT2-DAY1拓扑&#xff1a; 服务器IP及角色规划&#xff1a; 主机名 IP地址 角色 mysql11 192.168.4.11 MySQL数据库服务器 m…

人工智能 | 手工测试用例转Web自动化测试生成

简介 在传统编写 Web 自动化测试用例的过程中&#xff0c;基本都是需要测试工程师&#xff0c;根据功能测试用例转换为自动化测试的用例。市面上自动生成 Web 或 App 自动化测试用例的产品无非也都是通过录制的方式&#xff0c;获取操作人的行为操作&#xff0c;从而记录测试用…

游戏盾SDK真的能无视攻击吗

游戏盾SDK真的能无视攻击吗&#xff1f;在当今的互联网环境中&#xff0c;游戏行业蓬勃发展&#xff0c;但同时也面临着日益严峻的安全挑战。DDoS攻击、CC攻击、外挂作弊等恶意行为频发&#xff0c;不仅威胁着游戏的稳定性和公平性&#xff0c;也严重影响了玩家的游戏体验。为了…

Google Adsense账号被封怎么办?

海外营销广告通常依赖Google AdSense作为一种流行方法来获得流量。但是&#xff0c;如果您不小心&#xff0c;您的 AdSense 帐户可能会被禁止&#xff0c;让您失去创收的途径。下面我们将总结Google AdSense 帐户被封的常见原因原因以及如何解决此问题。 一、Google AdSense账号…