设计模式之策略模式(Strategy)

news2024/11/24 19:18:56

一、概述

定义一系列的算法,把它们一个个封装起来,并且使它们可相互替换。本模式使得算法可独立于使用它的类而变化。

二、适用性

1.许多相关的类仅仅是行为有异。“策略”提供了一种用多个行为中的一个行为来配置一个类的方法。

2.需要使用一个算法的不同变体。

3.使用算法的类不应该知道数据。可使用策略模式以避免暴露复杂的、与算法相关的数据结构。

4.一个类定义了多种行为,并且这些行为在这个类的操作中以多个条件语句的形式出现。 将相关的条件分支移入它们各自的Strategy类中以代替这些条件语句。

三、参与者

1.Strategy 定义所有支持的算法的公共接口。Context使用这个接口来调用某个ConcreteStrategy定义的算法。

2.ConcreteStrategy实现Strategy接口实现某具体算法。

3.Context 用一个ConcreteStrategy对象来配置。 维护一个Strategy对象的引用。 可定义一个接口让Strategy访问它的数据。

四、类图

五、示例

Strategy

public interface Strategy {
    void method();
}

ConcreteStrategy

public class StrategyImplA implements Strategy{
    @Override
    public void method() {
        System.out.println("这是第一个实现");
    }
}
public class StrategyImplB implements Strategy{
    @Override
    public void method() {
        System.out.println("这是第二个实现");
    }
}
public class StrategyImplC implements Strategy{
    @Override
    public void method() {
        System.out.println("这是第三个实现");
    }
}

Context

public class Context {

    private Strategy stra;

    public Context(Strategy stra) {
        this.stra = stra;
    }

    public void doMethod() {
        stra.method();
    }
}

自测

   @Test
   public void strategyTest() {
      Context ctx = new Context(new StrategyImplA());
      ctx.doMethod();
      ctx = new Context(new StrategyImplB());
      ctx.doMethod();
      ctx = new Context(new StrategyImplC());
      ctx.doMethod();
  }

自测结果 

Connected to the target VM, address: '127.0.0.1:7252', transport: 'socket'
这是第一个实现
这是第二个实现
这是第三个实现
Disconnected from the target VM, address: '127.0.0.1:7252', transport: 'socket'

六、实践

支付策略模式相关文件目录

 PayStrategy

/**
 * @author lyon
 * @createTime 2018年04月25日
 * @Description
 */
public interface PayStrategy {
    /**
     * 支付
     */
    void pay(BigDecimal money);
    /**
     * 申请退款
     */
    void refund(BigDecimal money);
    /**
     * 查询退款
     */
    void refundQuery();
    /**
     * 关闭订单
     */
    void close();
    /**
     * 查询订单
     */
    void query();
}

阿里支付相关-AliPayStrategy

/**
 * @author lyon
 * @createTime 2018年04月25日
 * @Description
 */
@Service("AliPayStrategy")
public class AliPayStrategy implements PayStrategy {
     /**
     * 根据app_id获取auth_code
     */
    public String getAuthCode(){
        return aliAuthUrl +"?app_id="+ali_app_id+"&redirect_uri="+ali_redirect_uri;
    }
    
    /**
     * 根据auth_code获取auth_token或刷新auth_token    grant_type:换取令牌    authorization_code;刷新令牌refresh_token
     */
    public String getAuthToken(String grant_type ,String auth_code)  {
        AlipayClient alipayClient = new DefaultAlipayClient(aliServiceUrl , ali_app_id , alipay_private_key,json, AboutCharset.UTF8,alipay_public_key,signType);
        AlipayOpenAuthTokenAppRequest request = new AlipayOpenAuthTokenAppRequest();
        request.setBizContent(
                //换取令牌
                "{\"grant_type\":"+grant_type+"\",\"code\":"+ auth_code +"}");
        AlipayOpenAuthTokenAppResponse response = null;
        try {
            response = alipayClient.execute(request);
        } catch (AlipayApiException e) {
            e.printStackTrace();
        }
        //略过判断response。获取appAuthToken
        String appAuthToken = response.getAppAuthToken();
        //查询授权信息
        //AlpayOpenAuthTokenAppQuery(appAuthToken);
        return appAuthToken;
    }

    @Override
    public void pay(BigDecimal money) {
       System.out.printf("支付宝支付了:%.2f元%n", money);
    }

    @Override
    public void refund(BigDecimal money) {
        System.out.printf("支付宝申请退款:%.2f元", money);
    }

    @Override
    public void refundQuery() {
        System.out.println("支付宝申请退款查询");
    }

    @Override
    public void close() {
        System.out.println("支付宝关闭订单");
    }

    @Override
    public void query() {
        System.out.println("支付宝查询订单");
    }
}

微信支付相关-WeChatPayStrategy

/**
 * @author lyon
 * @createTime 2018年04月25日
 * @Description
 */
@Service("WeChatPayStrategy")
public class WeChatPayStrategy implements PayStrategy {
    @Override
    public void pay(BigDecimal money) {
        System.out.printf("微信支付了:%.2f元%n", money);
    }

    @Override
    public void refund(BigDecimal money) {
        System.out.printf("微信申请退款:%.2f元", money);
    }

    @Override
    public void refundQuery() {
        System.out.println("微信申请退款查询");
    }

    @Override
    public void close() {
        System.out.println("微信关闭订单");
    }

    @Override
    public void query() {
        System.out.println("微信查询订单");
    }
}

建行龙支付

/**
 * @author lyon
 * @createTime 2018年04月26日
 * @Description
 */
@Service("CCBPayStrategy")
public class CCBPayStrategy implements PayChannelStrategy {
    String bankURL="https://ibsbjstar.ccb.com.cn/CCBIS/B2CMainPlat_00_ENPAY"; //建行支付默认网关
    String branchId = "xxxx"; //分行号固定

    public boolean signVerify(String pubKey, String src, String sign) {
        RSASig rsaSig = new RSASig();
        rsaSig.setPublicKey(pubKey);
        return rsaSig.verifySigature(sign,src);
    }

    @Override
    public void pay(BigDecimal money) {
        System.out.printf("建行龙支付支付了:%.2f元%n", money);
    }

    @Override
    public void refund(BigDecimal money) {
        System.out.printf("建行龙支付申请退款:%.2f元", money);
    }

    @Override
    public void refundQuery() {
        System.out.println("建行龙支付申请退款查询");
    }

    @Override
    public void close() {
        System.out.println("建行龙支付关闭订单");
    }

    @Override
    public void query() {
        System.out.println("建行龙支付查询订单");
    }
}

支付工厂

/**
 * @author lyon
 * @createTime 2018年04月26日
 * @Description
 */
@Component
public class PayStrategyFactory {

    private PayStrategyFactory(){}
    private static Map<String, PayChannelStrategy> map = new ConcurrentHashMap<>();

   static {
        map.put("wechat", new WeChatPayStrategy());
        map.put("ali", new AliPayStrategy());
        map.put("ccb", new CCBPayStrategy());
    }

    public static PayChannelStrategy getPayStrategy(String payType){
        return map.get(payType);
    }
}

自测

/**
 * @author lyon
 * @createTime 2018年04月25日
 * @Description
 */
public class TestStrategy {
    @Resource
    private PayStrategyFactory payStrategyFactory;
    @Test
    public void strategyTest() throws Exception {
       PayChannelStrategy payStrategy = payStrategyFactory.getPayStrategy("ali");
        if(null == payStrategy){
            throw new Exception( "支付类型为空") ;
        }
        BigDecimal money = new BigDecimal("12.01");
        payStrategy.pay(money);
    }
}

测试结果

Connected to the target VM, address: '127.0.0.1:11660', transport: 'socket'
支付宝支付了:12.01元
Disconnected from the target VM, address: '127.0.0.1:11660', transport: 'socket'

通过使用策略模式抽取公共接口,有统一的对外接口,在路由层通过查库获取配置的支付通道、使用不同的支付策略,实现业务和支付的分离,只用关注支付的不同实现,不用太多关注路由配置业务。

后续:PayStrategyFactory 支付工厂的改进。

/**
 * @author lyon
 * @createTime 2018年04月27日
 * @Description PayStrategy交由spring管理,使用动态代理,实现工厂支付接口
 *              使用@Scope(“prototype”)注解,可以通知Spring把被注解的Bean变成多例,防止线程不安全问题
 */
@Configuration
public class PayContextConfig {
    @Bean
    public ServiceLocatorFactoryBean serviceLoaderFactoryBean(){
        ServiceLocatorFactoryBean loaderFactoryBean = new ServiceLocatorFactoryBean();
        loaderFactoryBean.setServiceLocatorInterface(PayChannelStrategy.class);
        return loaderFactoryBean;
    }

    @Bean("wechat")
    @Scope("prototype")
    public WeChatPayStrategy weChatPayStrategy(){
        return  new WeChatPayStrategy();
    }

    @Bean("ali")
    @Scope("prototype")
    public AliPayStrategy aliPayStrategy(){
        return  new AliPayStrategy();
    }

    @Bean("ccb")
    @Scope("prototype")
    public CCBPayStrategy ccbPayStrategy(){
        return  new CCBPayStrategy();
    }
}

测试:

@Test
public void strategyTest() throws Exception {
    AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(PayContextConfig.class);
    try {
            PayChannelStrategy payStrategy = (PayChannelStrategy) applicationContext.getBean("ccb");
            BigDecimal money = new BigDecimal("12.01");
            payStrategy.pay(money);
        }catch (Exception e){
            throw new Exception( "支付类型为空") ;
     }
}

测试结果:

14:50:50.998 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'serviceLoaderFactoryBean'
建行龙支付支付了:12.01元

PS:在此实际工作过程中,不仅承担运维架构核心开发等还得承担绝大部分开发任务,耐心解答成员各种问题、分享封装后如何使用、建议如何优化改进等;还帮忙解决各种问题。不止微服务可高并发,单机也可高并发。架构是跟着业务需求和现实问题持续演进。

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

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

相关文章

Crowd-Robot Interaction 论文阅读

论文信息 题目&#xff1a;Crowd-Robot Interaction:Crowd-aware Robot Navigation with Attention-based Deep Reinforcement Learning 作者&#xff1a;Changan Chen, Y uejiang Liu 代码地址&#xff1a;https://github.com/vita-epfl/CrowdNav 来源&#xff1a;arXiv 时间…

面试测试开发被问到数据库索引不知道怎么办?

提出的问题 什么情况下创建索引&#xff0c;什么时候不需要索引&#xff1f; 索引的种类有哪些&#xff1f; 什么是索引 索引就是帮助数据库管理系统高效获取数据的数据结构&#xff0c;就好比一本书的目录&#xff0c;它可以帮我们快速进行特定值的定位与查找&#xff0c;…

软件架构师高级——3、数据库系统

• 数据库概述&#xff08;★★★&#xff09; 集中式数据库系统 •数据管理是集中的 •数据库系统的素有功能 &#xff08;从形式的用户接口到DBMS核心&#xff09; 者口集中在DBMS所在的计算机。 B/S结构 •客户端负责数据表示服务 •服务器主要负责数据库服务 •数据 和后端…

IC人才“疯狂”抢购:月薪开到7.5万的背后是什么?

随着人工智能和电动汽车等技术的快速发展&#xff0c;集成电路&#xff08;IC&#xff09;人才成为汽车行业的抢手货。近年来&#xff0c;车企对于IC人才的需求越来越大&#xff0c;导致月薪飙升到了7.5万的惊人高薪水。这个话题引起了广泛关注&#xff0c;下面我们将从供需关系…

卤味行业市场分析,绝味、周黑鸭、嘴尚绝谁能脱颖而出

随着人们生活水平的提高&#xff0c;卤味市场不断发展壮大&#xff0c;成为我国食品行业中一个重要的组成部分。根据国家统计局数据&#xff0c;截至2020年底&#xff0c;我国卤味店数量已经达到了8.4万家&#xff0c;总产值超过1600亿元。 卤味行业的特点 产品口味丰富&#…

布基纳法索ECTN(BESC)申请流程

根据BURKINA FASO布基纳法索签发于 11/07/2006法令编号 00557的规定: 自2006年11月07 日起所有出口至布基纳法索&#xff08;Burkina Faso&#xff09;的货物&#xff0c;必须申请ECTN/BESC。ECTN是ELECTRONIC CARGO TRACKING NOTE的英文缩写&#xff0c;BESC是BORDEREAU DE SU…

《大型网站技术架构设计》第二篇 架构-性能

不同视角下的网站性能 1、用户 从用户角度&#xff0c;网站性能就是用户在浏览器上直观感受到的网站响应速度快还是慢。用户感受到的时间。 2、开发人员 开发人员关注的主要是应用程序本身及其相关子系统的性能&#xff0c;包括响应延迟、系统吞吐量、并发处理能力、系统稳定…

Redis实战案例25-附近商铺功能

1. GEO数据结构 Redis中Geohash功能应用 添加地理坐标 求两点之间距离 搜索天安门附近10km的火车站&#xff0c;按升序 2. 导入店铺数据到GEO Redis中存储店铺的信息&#xff0c;将店铺的id和经纬度坐标存到GEO数据类型中去&#xff0c;其中member存id&#xff0c;经纬度对应…

关于自动化测试用例失败重试的一些思考

自动化测试用例失败重跑有助于提高自动化用例的稳定性&#xff0c;那我们来看一下&#xff0c;python和java生态里都有哪些具体做法&#xff1f; 怎么做 如果是在python生态里&#xff0c;用pytest做测试驱动&#xff0c;那么可以通过pytest的插件pytest-rerunfailures来实现…

第十三次CCF计算机软件能力认证

第一题&#xff1a;跳一跳 近来&#xff0c;跳一跳这款小游戏风靡全国&#xff0c;受到不少玩家的喜爱。 简化后的跳一跳规则如下&#xff1a;玩家每次从当前方块跳到下一个方块&#xff0c;如果没有跳到下一个方块上则游戏结束。 如果跳到了方块上&#xff0c;但没有跳到方块的…

Python(七十一)集合的概述与创建

❤️ 专栏简介&#xff1a;本专栏记录了我个人从零开始学习Python编程的过程。在这个专栏中&#xff0c;我将分享我在学习Python的过程中的学习笔记、学习路线以及各个知识点。 ☀️ 专栏适用人群 &#xff1a;本专栏适用于希望学习Python编程的初学者和有一定编程基础的人。无…

自然语言处理:长文本场景下的关键词抽取实践

NLP专栏简介:数据增强、智能标注、意图识别算法|多分类算法、文本信息抽取、多模态信息抽取、可解释性分析、性能调优、模型压缩算法等 专栏详细介绍:NLP专栏简介:数据增强、智能标注、意图识别算法|多分类算法、文本信息抽取、多模态信息抽取、可解释性分析、性能调优、模型…

第四章 kernel函数基础篇

cuda教程目录 第一章 指针篇 第二章 CUDA原理篇 第三章 CUDA编译器环境配置篇 第四章 kernel函数基础篇 第五章 kernel索引(index)篇 第六章 kenel矩阵计算实战篇 第七章 kenel实战强化篇 第八章 CUDA内存应用与性能优化篇 第九章 CUDA原子(atomic)实战篇 第十章 CUDA流(strea…

【Python ezdxf+matplotlib】显示AutoCAD导出的.dxf格式文件

代码&#xff1a; import ezdxf,matplotlib import matplotlib.pyplot as plt from matplotlib.patches import Polygon matplotlib.use(TkAgg) # 避免Matplotlib版本与其他相关库的兼容性问题def display_dxf(file_path):doc ezdxf.readfile(file_path)msp doc.modelspac…

Maven命令启动SpringBoot项目

用Maven命令启动SpringBoot项目&#xff0c;记录如下&#xff1a; mvn spring-boot:run C:\Users\Administrator\source\repos\kd-datacenter\server\kd-datacenter>mvn spring-boot:run

HBase-组成

client 读写请求HMaster 管理元数据监控region是否需要进行负载均衡&#xff0c;故障转移和region的拆分RegionServer 负责数据cell的处理&#xff0c;例如写入数据put&#xff0c;查询数据get等 拆分合并Region的实际执行者&#xff0c;由Master监控&#xff0c;由regionServ…

Idea中maven无法下载源码

今天在解决问题的时候想要下载源码&#xff0c;突然发现idea无法下载&#xff0c;这是真的蛋疼&#xff0c;没办法查看原因&#xff0c;最后发现问题的原因居然是因为Maven&#xff0c;由于我使用的idea的内置的Bundle3的Maven&#xff0c;之前没有研究过本地安装和内置的区别&…

MyBatis-动态SQL-foreach

目录 标签有以下常用属性&#xff1a; 小结 <froeach> <foreach>标签有以下常用属性&#xff1a; collection&#xff1a;指定要迭代的集合或数组的参数名&#xff08;遍历的对象&#xff09;。item&#xff1a;指定在迭代过程中的每个元素的别名&#xff08;遍历…

D. Productive Meeting

Example input 8 2 2 3 3 1 2 3 4 1 2 3 4 3 0 0 2 2 6 2 3 0 0 2 5 8 2 0 1 1 5 0 1 0 0 6 output 2 1 2 1 2 3 1 3 2 3 2 3 5 1 3 2 4 2 4 3 4 3 4 0 2 1 2 1 2 0 4 1 2 1 5 1 4 1 2 1 5 2 解析&#xff1a; 贪心&#xff0c;每次选择两个剩余次数最多的人&#xff0c;并…

使用hutool工具生成树形结构

假设要构建一个菜单&#xff0c;可以实现智慧库房&#xff0c;菜单的样子如下&#xff1a; 智慧库房|- RFID|- 智慧大屏|- 智能密集架|- 环境管控那这种结构如何保存在数据库中呢&#xff1f;一般是这样的&#xff1a; ​ 每条数据根据parentId相互关联并表示层级关系&#x…