【设计模式之美】策略模式方法论:解耦策略的定义、创建和使用

文章目录

  • 一. 策略的定义-封装策略,面向接口
  • 二. 策略的创建-创建策略工厂
    • 1. 对于无状态策略
    • 2. 对于有状态策略
  • 三. 策略的使用:动态选择
  • 四. 避免分支判断-策略的优雅
    • 1. 对于无状态的策略
    • 2. 对于有状态的策略

 


策略模式是定义一族算法类,将每个算法分别封装起来,让它们可以互相替换。策略模式可以使算法的变化独立于使用它们的客户端(这里的客户端代指使用算法的代码)。

它解耦的是策略的定义、创建、使用这三部分。接下来我们看一下这三个部分的逻辑与要解决的问题


 

一. 策略的定义-封装策略,面向接口

策略类的定义比较简单,包含一个策略接口和一组实现这个接口的策略类。它是面向接口编程,所以可以灵活替换不同的策略。

public interface Strategy {void algorithmInterface();
}public class ConcreteStrategyA implements Strategy {@Overridepublic void  algorithmInterface() {//具体的算法...}
}public class ConcreteStrategyB implements Strategy {@Overridepublic void  algorithmInterface() {//具体的算法...}
}

二. 策略的创建-创建策略工厂

策略模式会包含一组策略,具体使用哪个策略,可以通过type来选定。我们可以把一组策略放到放到工厂类。

1. 对于无状态策略

策略模式是否有状态

如果策略类是无状态的,不包含成员变量,只是纯粹的算法实现,这样的策略对象是可以被共享使用的,不需要在每次调用 getStrategy() 的时候,都创建一个新的策略对象。即如上我们提前创建好每个策略对象,缓存到工厂类中,用的时候直接返回。

public class StrategyFactory {private static final Map<String, Strategy> strategies = new HashMap<>();static {strategies.put("A", new ConcreteStrategyA());strategies.put("B", new ConcreteStrategyB());}public static Strategy getStrategy(String type) {... check somereturn strategies.get(type);}
}

 

2. 对于有状态策略

如果策略类是有状态的,每次获取工厂中获取的策略都是新的策略对象。那可以如下创建:

public class StrategyFactory {public static Strategy getStrategy(String type) {if (type == null || type.isEmpty()) {throw new IllegalArgumentException("type should not be empty.");}if (type.equals("A")) {return new ConcreteStrategyA();} else if (type.equals("B")) {return new ConcreteStrategyB();}return null;}
}

 

三. 策略的使用:动态选择

选定某一策略,一般根据业务逻辑,动态的选定某一个策略。

// 策略接口:EvictionStrategy
// 策略类:LruEvictionStrategy、FifoEvictionStrategy、LfuEvictionStrategy...
// 策略工厂:EvictionStrategyFactorypublic class UserCache {private Map<String, User> cacheData = new HashMap<>();private EvictionStrategy eviction;public UserCache(EvictionStrategy eviction) {this.eviction = eviction;}//...
}// 运行时动态确定,根据配置文件的配置决定使用哪种策略
public class Application {public static void main(String[] args) throws Exception {EvictionStrategy evictionStrategy = null;Properties props = new Properties();props.load(new FileInputStream("./config.properties"));String type = props.getProperty("eviction_type");evictionStrategy = EvictionStrategyFactory.getEvictionStrategy(type);UserCache userCache = new UserCache(evictionStrategy);//...}
}//或者直接根据type动态选择

 

四. 避免分支判断-策略的优雅

能够移除分支判断逻辑的模式不仅仅有策略模式,状态模式也可以。

如下判断分支:

public class OrderService {public double discount(Order order) {double discount = 0.0;OrderType type = order.getType();if (type.equals(OrderType.NORMAL)) { // 普通订单//...省略折扣计算算法代码} else if (type.equals(OrderType.GROUPON)) { // 团购订单//...省略折扣计算算法代码} else if (type.equals(OrderType.PROMOTION)) { // 促销订单//...省略折扣计算算法代码}return discount;}
}

 

1. 对于无状态的策略

对上面的代码重构,将不同的逻辑设计成策略类,并由工厂类来负责创建策略对象。然后通过map码表来动态选择策略。这样就没有了 if-else 分支判断语句了。

// 策略的定义
public interface DiscountStrategy {double calDiscount(Order order);
}
// 省略NormalDiscountStrategy、GrouponDiscountStrategy、PromotionDiscountStrategy类代码...// 策略的创建
public class DiscountStrategyFactory {private static final Map<OrderType, DiscountStrategy> strategies = new HashMap<>();static {strategies.put(OrderType.NORMAL, new NormalDiscountStrategy());strategies.put(OrderType.GROUPON, new GrouponDiscountStrategy());strategies.put(OrderType.PROMOTION, new PromotionDiscountStrategy());}public static DiscountStrategy getDiscountStrategy(OrderType type) {return strategies.get(type);}
}// 策略的使用
public class OrderService {public double discount(Order order) {OrderType type = order.getType();DiscountStrategy discountStrategy = DiscountStrategyFactory.getDiscountStrategy(type);return discountStrategy.calDiscount(order);}
}

 

2. 对于有状态的策略

对于有状态的策略,将判断逻辑放到了工厂类中

public class DiscountStrategyFactory {public static DiscountStrategy getDiscountStrategy(OrderType type) {if (type == null) {throw new IllegalArgumentException("Type should not be null.");}if (type.equals(OrderType.NORMAL)) {return new NormalDiscountStrategy();} else if (type.equals(OrderType.GROUPON)) {return new GrouponDiscountStrategy();} else if (type.equals(OrderType.PROMOTION)) {return new PromotionDiscountStrategy();}return null;}
}

 

参考:《设计模式之美》–王争

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

UnityHub 无法添加模块问题

文章目录 1.问题描述2.问题解决 1.问题描述 在Hub中无法添加模块 2.问题解决 1、点击设置 2、设置版本安装位置 可以发现installs的安装位置路径设置不是unity安装位置&#xff0c;这里我们更改成自己电脑unity安装位置的上一级路径 添加模块正常&#xff1a;

aws sap认证考试如何轻松通过

如何高效备考AWS SAP (Solutions Architect Professional) 认证? AWS SAP认证是AWS认证体系中难度最高的认证之一,要通过这个考试确实需要下一番功夫。但通过合理规划和有效准备,你可以提高通过的几率。以下是一些建议: 评估起点 首先诚实地评估自己的AWS知识水平和实践经验。…

three完全开源扩展案例02-跳动的音乐

更多案例尽在https://threelab.cn/ 演示地址 import * as THREE from "three"; import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";let mediaElement; let analyser; let scene; let camera; let renderer; let controls; …

STM32中断(NVIC和EXIT)

CM3 内核支持 256 个中断&#xff0c;其中包含了 16 个内核中断和 240个外部中断&#xff0c;并且具有 256 级的可编程中断设置。但STM32 并没有使用CM3内核的全部东西&#xff0c;而是只用了它的一部分。STM32有 76 个中断&#xff0c;包括16 个内核中断和 60 个可屏蔽中断&am…

Codeforces Round 954 (Div. 3)(A~D题)

A. X Axis 思路: 1~10暴力枚举一下所有可能 代码: #include<bits/stdc.h> using namespace std; #define N 1000005 typedef long long ll; typedef unsigned long long ull; ll n, m, t, h, k; ll a, b, c; ll ans, num, sum, cnt; ll temp[N], f1[N], f2[N]; bool f…

无头单向非循环链表实现 and leetcode刷题

无头单向非循环链表实现 1. 单链表的模拟实现IList.java接口&#xff1a;MySingleList.java文件&#xff1a; 2. leetcode刷题2.1 获取链表的中间节点2.2 删除链表中所有值为value的元素2.3 单链表的逆置2.4 获取链表倒数第k个节点2.5 给定 x, 把一个链表整理成前半部分小于 x,…

java使用easypoi模版导出word详细步骤

文章目录 第一步、引入pom依赖第二步、新建导出工具类WordUtil第三步、创建模版word4.编写接口代码5.导出结果示例 第一步、引入pom依赖 <dependency><groupId>cn.afterturn</groupId><artifactId>easypoi-spring-boot-starter</artifactId><…

AutoMQ vs Kafka: 来自小红书的独立深度评测与对比

测试背景 当前小红书消息引擎团队与 AutoMQ 团队正在深度合作&#xff0c;共同推动社区建设&#xff0c;探索云原生消息引擎的前沿技术。本文基于 OpenMessaging 框架&#xff0c;对 AutoMQ 进行了全面测评。欢迎大家参与社区并分享测评体验。 01 测试结论 本文主要测评云…

Elon Musk开源Grok

转载自&#xff1a;AILab基地 早在6天前&#xff0c;马斯克就发文称xAI将开源Grok 图片 13小时前&#xff0c;马斯克开源了旗下公司X的Grok训练模型&#xff0c;并喊话OpenAI&#xff0c;你名字里的Open到底在哪里 图片 下面是xai-org的GitHub开源地址[https://github.com/x…

yolov8、RTDETR无法使用多个GPU训练

yolov8、RTDETR无法使用多个GPU训练 网上看了好多解决方法&#xff1a; 什么命令行 CUDA_VISIBLE_DEVICES0,1 python train.py 环境变量都不行 最后找到解决方案&#xff1a;在ultralytics/engine/trainer.py 中的第246行 将 self.model DDP(self.model, device_ids[RANK])…

学习测试7-ADB的使用

ADB是什么&#xff1f; ADB&#xff0c;即 Android Debug Bridge&#xff08;安卓调试桥&#xff09; 是一种允许模拟器或已连接的 Android 设备进行通信的命令行工具&#xff0c;它可为各种设备操作提供便利&#xff0c;如安装和调试应用&#xff0c;并提供对 Unix shell&…

C++|智能指针

目录 引入 一、智能指针的使用及原理 1.1RAII 1.2智能指针原理 1.3智能指针发展 1.3.1std::auto_ptr 1.3.2std::unique_ptr 1.3.3std::shared_ptr 二、循环引用问题及解决方法 2.1循环引用 2.2解决方法 三、删除器 四、C11和boost中智能指针的关系 引入 回顾上…

如何分析软件测试中发现的Bug!

假如你是一名软件测试工程师&#xff0c;每天面对的就是那些“刁钻”的Bug&#xff0c;它们像是隐藏在黑暗中的敌人&#xff0c;时不时跳出来给你一个“惊喜”。那么&#xff0c;如何才能有效地分析和处理这些Bug&#xff0c;让你的测试工作变得高效且有趣呢&#xff1f;今天我…

SpringBoot配置flyway

背景 目前我们的项目代码都会交由Git、SVN等版本管理工具进行管理&#xff0c;但是我们的sql脚本&#xff0c;尤其是各类ddl脚本并没有进行版本的管理&#xff08;python的web框架Django默认就提供了类似的工具&#xff0c;从一开始就鼓励开发者通过版本管理的方式进行数据库的…

Android Studio 的Gradle下载慢,Gradle切换下载源

看图 下面的文字地址因为转义符号的问题&#xff0c;https后面少了一个斜杠看图片进行补充&#xff0c;直接复制不知道能不能用 distributionUrlhttps://mirrors.cloud.tencent.com/gradle/gradle-8.7-bin.zip

第一关:Linux基础知识

Linux基础知识目录 前言LinuxInternStudio 关卡1. InternStudio开发机介绍2. SSH及端口映射2.1 什么是SSH&#xff1f;2.2 如何使用SSH远程连接开发机&#xff1f;2.2.1 使用密码进行SSH远程连接2.2.2 配置SSH密钥进行SSH远程连接2.2.3 使用VScode进行SSH远程连接 2.3. 端口映射…

进度条提示-在python程序中使用避免我误以为挂掉了

使用库tqdm 你还可以手写一点&#xff0c;反正只要是输出点什么东西都可以&#xff1b; Demo from chatgpt import time from tqdm import tqdm# 示例函数&#xff0c;模拟长时间运行的任务 def long_running_task():total_steps 100for step in tqdm(range(total_steps), …

手机容器化 安装docker

旧手机-基于Termux容器化 1、安装app 在手机上安装Termux或ZeroTermux&#xff08;Termux扩展&#xff09; 1.1 切换源 注&#xff1a;可以将termux进行换源&#xff0c;最好采用国内源&#xff0c;例如&#xff1a;清华源等 更新包列表和升级包&#xff08;可选&#xff0…

vue 画二维码及长按保存

需求 想要做如下图的二维码带文字&#xff0c;且能够长按保存 前期准备 一个canvas安装qrcode&#xff08;命令&#xff1a;npm i qrcode&#xff09; 画二维码及文字 初始化画布 <template><div><canvas ref"canvas" width"300" he…

8627 数独

为了判断数独解是否合法&#xff0c;我们需要遵循以下步骤&#xff1a; 1. **检查每一行**&#xff1a;确保1到9每个数字在每一行中只出现一次。 2. **检查每一列**&#xff1a;确保1到9每个数字在每一列中只出现一次。 3. **检查每个3x3的宫**&#xff1a;确保1到9每个数字在…