当前位置: 首页 > news >正文

最实用的设计模式:策略模式的快速理解

(一)什么是策略模式

策略模式是设计模式中一个相对来说比较好理解,应用也十分广泛的设计模式。在我工作这些年所接触的项目中,有一个项目在整体上就使用了策略模式。在百科上,针对策略模式是这样介绍的:策略模式指对象有某个行为,但是在不同的场景中,该行为有不同的实现算法。

以某火锅品牌为例,同样是最后的收费环节,学生周末8.8折,工作日的指定时间6.9折,非学生全额支付。同样的收费方式在不同的情况下有不同的计算方式,这里就可以使用策略模式来实现。

(二)策略模式中的几个角色

在策略模式中,有三种角色:

抽象策略(Strategy):定义实现策略所需要的接口。一般是定义接口或者抽象类。

具体策略(ConcreteStrategy):抽象策略的具体实现类,在策略模式中,每个算法都是一个具体策略。

上下文(Context):负责使用策略的角色,屏蔽高层模块对策略的直接访问。

(三)策略模式的具体案例

还是以最开始的火锅店为例子。首先定义一个收费的策略接口,定义收费的方法:

public interface BillingStrategy {
    void billing(BigDecimal amount);
}

接着写两个具体的策略:

// 周末8.8折
public class StudentWeekend implements BillingStrategy{
    @Override
    public void billing(BigDecimal amount) {
        System.out.println("收了"+amount.multiply(new BigDecimal("0.88"))+"元");
    }
}
// 工作日6.9折
public class StudentWorkingDay implements BillingStrategy{
    @Override
    public void billing(BigDecimal amount) {
        System.out.println("收了"+amount.multiply(new BigDecimal("0.69"))+"元");
    }
}

接着定义上下文角色,在这个例子中,负责使用策略的角色是火锅店:

public class Restaurant {
    private BillingStrategy billingStrategy;

    public Restaurant(BillingStrategy billingStrategy){
        this.billingStrategy = billingStrategy;
    }

    public void billing(BigDecimal amount){
        billingStrategy.billing(amount);
    }
}

最后在Main方法中进行调用:

public class Main {
    public static void main(String[] args) {
        Restaurant restaurant1 = new Restaurant(new StudentWeekend());
        restaurant1.billing(new BigDecimal("200"));

        Restaurant restaurant2 = new Restaurant(new StudentWorkingDay());
        restaurant2.billing(new BigDecimal("200"));
    }
}

从结果可以看出,同样的收费方式,当传入的策略不同时,就可以采取不同的算法。

(四)策略模式在源码中的应用

策略模式在开源代码和JDK源码中的应用十分广泛。

比如TreeMap在构造方法中引入Comparator排序策略,在put方法时根据不同的排序策略执行不同的排序方法:


又比如ThreadPoolExecutor这个线程池的类,在构造方法中传入拒绝策略,在reject方法中根据不同的拒绝策略执行具体的拒绝方法:


(五)策略模式的理解

其实不使用设计模式,一样可以写代码,甚至可以写的更简单,但是设计模式考虑的是代码的扩展和可维护性。

策略模式最大的优点是很方便地替换策略,甚至还可以在程序运行过程中切换策略,也遵循了设计模式中的开闭原则,即对扩展开放,对封闭关闭。缺点是每新增一个策略就需要新增一个类,另外客户端必须知道所有的策略类。

相关文章:

  • Spark算子实战Java版,学到了
  • 精益 React 学习指南 (Lean React)- 1.5 React 与 DOM
  • 【设计模式】快速理解装饰者模式,及其在JDK源码中的应用
  • 你真的了解Maven吗?
  • 【转】Xcode常用快捷键与技巧分享
  • 【设计模式】快速理解观察者模式,原来它还有这么多其他名字
  • linux实际应用小技巧
  • 时间类有多复杂,JDK竟设计了三版
  • AOP之PostSharp5-LocationInterceptionAspect
  • 如何快速学习一门新技术
  • 模拟实现部分库函数(strcpy,strcmp,strcat,strstr,memcpy,memmove,memset)
  • 组成原理(一):计算机是如何组成的
  • JDK9相比于JDK8,究竟变强了多少
  • Hive之分区(Partitions)和桶(Buckets)
  • 列式存储?OLAP?ClickHouse究竟是何方神圣
  • Android交互
  • ES6简单总结(搭配简单的讲解和小案例)
  • Javascripit类型转换比较那点事儿,双等号(==)
  • LeetCode18.四数之和 JavaScript
  • 从 Android Sample ApiDemos 中学习 android.animation API 的用法
  • 分布式事物理论与实践
  • 分享一个自己写的基于canvas的原生js图片爆炸插件
  • 回顾 Swift 多平台移植进度 #2
  • 基于HAProxy的高性能缓存服务器nuster
  • 全栈开发——Linux
  • 限制Java线程池运行线程以及等待线程数量的策略
  • 项目管理碎碎念系列之一:干系人管理
  • 一个SAP顾问在美国的这些年
  • 译有关态射的一切
  • ​2020 年大前端技术趋势解读
  • ​LeetCode解法汇总2808. 使循环数组所有元素相等的最少秒数
  • $.ajax()方法详解
  • $.each()与$(selector).each()
  • (1)(1.13) SiK无线电高级配置(六)
  • (2)关于RabbitMq 的 Topic Exchange 主题交换机
  • (4.10~4.16)
  • (6)设计一个TimeMap
  • (Redis使用系列) Springboot 整合Redisson 实现分布式锁 七
  • (非本人原创)我们工作到底是为了什么?​——HP大中华区总裁孙振耀退休感言(r4笔记第60天)...
  • (附源码)php新闻发布平台 毕业设计 141646
  • (附源码)ssm高校升本考试管理系统 毕业设计 201631
  • (每日持续更新)jdk api之FileReader基础、应用、实战
  • (三)mysql_MYSQL(三)
  • (十二)springboot实战——SSE服务推送事件案例实现
  • (算法)Travel Information Center
  • (转)mysql使用Navicat 导出和导入数据库
  • (转)shell中括号的特殊用法 linux if多条件判断
  • * 论文笔记 【Wide Deep Learning for Recommender Systems】
  • ./indexer: error while loading shared libraries: libmysqlclient.so.18: cannot open shared object fil
  • .net core 实现redis分片_基于 Redis 的分布式任务调度框架 earth-frost
  • .NET 材料检测系统崩溃分析
  • .NET/C# 阻止屏幕关闭,阻止系统进入睡眠状态
  • .netcore 6.0/7.0项目迁移至.netcore 8.0 注意事项
  • .NET构架之我见
  • .NET业务框架的构建