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

一、概述

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

二、适用性

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Grafana V10 告警推送

最近项目建设完成&#xff0c;一个城域网项目&#xff0c;相关zabbix和grafana展示已经完&#xff0c;想了想&#xff0c;不想天天看平台去盯网络监控平台&#xff0c;索性对告警进行分类调整&#xff0c;增加告警的推送&#xff0c;和相关部门的提醒&#xff0c;其他部门看不懂…

Collections工具类(java)

文章目录 7.1 常用方法 参考操作数组的工具类&#xff1a;Arrays&#xff0c;Collections 是一个操作 Set、List 和 Map 等集合的工具类。 7.1 常用方法 Collections 中提供了一系列静态的方法对集合元素进行排序、查询和修改等操作&#xff0c;还提供了对集合对象设置不可变、…

基于Mediapipe的姿势识别并同步到Unity人体模型中

如题&#xff0c;由于是商业项目&#xff0c;无法公开源码&#xff0c;这里主要说一下实现此功能的思路。 人体关节点识别 基于Mediapipe Unity插件进行开发&#xff0c;性能比较低的CPU主机&#xff0c;无法流畅地运行Mediapipe&#xff0c;这个要注意一下。 Mediapipe33个人体…

Microsoft Message Queuing Denial-of-Service Vulnerability

近期官方公布了一个MSMQ的拒绝服务漏洞&#xff0c;可能因为网络安全设备的更新&#xff0c;影响业务&#xff0c;值得大家关注。 漏洞具体描述参见如下&#xff1a; Name: Microsoft Message Queuing Denial-of-Service Vulnerability Description: Microsoft Message Queuing…

AI一键生成短视频

AI一键生成推文短视频 阅读时长&#xff1a;10分钟 本文内容&#xff1a; 结合开源AI&#xff0c;一键生成短视频发布到常见的某音&#xff0c;某手平台&#xff0c;狠狠赚一笔 前置知识&#xff1a; 1.基本的 python 编程知识 2.chatGPT 使用过 3.stable diffution 使用过 成果…

8.3一日总结

1.远程仓库的使用 a.克隆远程仓库 1>.在桌面克隆远程仓库 git clone 仓库名 2>.修改仓库内容 3>添加目录 git add. 4>提交: git commit -m 完成登录功能 5>推送提交远程仓库 : git push origin master -u 6>更改推送:git push(简写形式) 需要先添加,再提交,最…

怎么加密文件夹才更安全?安全文件夹加密软件推荐

文件夹加密可以让其中数据更加安全&#xff0c;但并非所有加密方式都能够提高极高的安全强度。那么&#xff0c;怎么加密文件夹才更安全呢&#xff1f;下面我们就来了解一下那些安全的文件夹加密软件。 文件夹加密超级大师 如果要评选最安全的文件夹加密软件&#xff0c;那么文…

FineBI 人力资源 专题

此处使用FineBI处理人力资源数据&#xff0c;数据来源于HR_database数据文件&#xff0c;将此文件拷贝到安装目录下 然后配置数据库连接 在【公共数据】中新建一个文件夹&#xff0c;并将之前数据库中需要用到的表放入此处&#xff0c;更新数据。显示如下。 这时候首先要建立…

goanno的简单配置-goland配置

手动敲注释太LOW,使用插件一步搞定 goanno 打开goanno的配置 点击之后弹窗如下 配置method /** Title ${function_name} * Description ${todo} * Author zhangguofu ${date} * Param ${params} * Return ${return_types} */相关效果如下 同理配置interface // ${interface…

使用TransBigData快速高效地处理、分析、挖掘出租车GPS数据

01、TransBigData简介 TransBigData是一个为交通时空大数据处理、分析和可视化而开发的Python包。TransBigData为处理常见的交通时空大数据&#xff08;如出租车GPS数据、共享单车数据和公交车GPS数据等&#xff09;提供了快速而简洁的方法。TransBigData为交通时空大数据分析的…

一篇万能英语作文范文怎么写?聪明灵犀英语作文写作工具分享

一篇万能英语作文范文怎么写&#xff1f;英语作文是英语学习中不可或缺的一环&#xff0c;但是对于很多人来说&#xff0c;写作并不是一件容易的事情。本文将分享一些实用的英语作文写作工具&#xff0c;帮助你更好地写作。 1. 明确主题 写作之前&#xff0c;首先需要明确主题…

一文让你了解网络安全和云安全的区别与联系

相信大家对于网络安全和云安全的关系不是很了解&#xff0c;今天小编就和大家来一起聊聊网络安全和云安全的区别与联系&#xff0c;仅供参考哦&#xff01; 网络安全和云安全的区别 1、两者定义不同。网络安全通常指计算机网络的安全&#xff0c;实际上也可以指计算机通信网络…

Go Windows下开发环境配置(图文)

Go Windows下开发环境配置 下载 安装 点击下载的安装包进行安装。安装路径可以选择到自己的目录。 环境变量配置 GOROOT&#xff1a;&#xff08;指定到安装目录下&#xff09; GOPATH&#xff1a;&#xff08;是工作空间&#xff09; path&#xff1a;在安装时已经添加了…

日撸java三百行day81-83

文章目录 说明CNN卷积神经网络1. 什么是CNN&#xff08;CNN基础知识&#xff09;1. 基本概念2.输入层3.卷积层3.1 图像3.2 卷积核3.3 偏置数3.4 滑动窗口步长3.5 特征图个数&#xff08;特征图通道数或深度&#xff09;3.6 边缘填充3.7 卷积过程例子 4. 激活函数5. 池化层6.全连…

bagging集成与boosting集成的区别是什么?

bagging集成与boosting集成的区别 区别一:数据方面 Bagging&#xff1a;对数据进行采样训练; Boosting&#xff1a;根据前一轮学习结果调整数据的重要性。 区别二:投票方面 Bagging&#xff1a;所有学习器平权投票; Boosting&#xff1a;对学习器进行加权投票。 区别三:…

Maven-生命周期及命令

关于本文 ✍写作原因 之前在学校学习的时候&#xff0c;编写代码使用的项目都是单体架构&#xff0c;导入开源框架依赖时只需要在pom.xml里面添加依赖&#xff0c;点一下reload按钮即可解决大部分需求&#xff1b;但是在公司使用了dubbo微服务架构之后发现只知道使用reload不足…

网络安全--原型链污染

目录 1.什么是原型链污染 2.原型链三属性 1&#xff09;prototype 2)constructor 3)__proto__ 4&#xff09;原型链三属性之间关系 3.JavaScript原型链继承 1&#xff09;分析 2&#xff09;总结 3)运行结果 4.原型链污染简单实验 1&#xff09;实验一 2&#xff0…

回归预测 | MATLAB实现POA-CNN-LSTM鹈鹕算法优化卷积长短期记忆神经网络多输入单输出回归预测

回归预测 | MATLAB实现POA-CNN-LSTM鹈鹕算法优化卷积长短期记忆神经网络多输入单输出回归预测 目录 回归预测 | MATLAB实现POA-CNN-LSTM鹈鹕算法优化卷积长短期记忆神经网络多输入单输出回归预测预测效果基本介绍模型描述程序设计参考资料 预测效果 基本介绍 MATLAB实现POA-CNN…

【Linux】多路转接 -- select函数

文章目录 1. 认识select函数2. select函数原型3. socket就绪条件4. select工作流程5. select服务器6. select的优缺点 首先我们要了解一下&#xff0c;什么是多路转接&#xff1f; 多路转接也叫多路复用&#xff0c;是一种用于管理多个IO通道的技术。它能实现同时监听和处理多个…

《动手学深度学习》优化算法学习习题

优化算法 梯度下降类 小批量随机梯度下降&#xff0c;通过平均梯度来减小方差 动量法 基础 泄露平均法&#xff1a;用来取代梯度的计算 β \beta β这个参数控制了取多久时间的平均值 上述推理构成了”加速”梯度方法的基础&#xff0c;例如具有动量的梯度。 在优化问题…