设计模式之策略模式(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{@Overridepublic void method() {System.out.println("这是第一个实现");}
}
public class StrategyImplB implements Strategy{@Overridepublic void method() {System.out.println("这是第二个实现");}
}
public class StrategyImplC implements Strategy{@Overridepublic void method() {System.out.println("这是第三个实现");}
}

Context

public class Context {private Strategy stra;public Context(Strategy stra) {this.stra = stra;}public void doMethod() {stra.method();}
}

自测

   @Testpublic 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。获取appAuthTokenString appAuthToken = response.getAppAuthToken();//查询授权信息//AlpayOpenAuthTokenAppQuery(appAuthToken);return appAuthToken;}@Overridepublic void pay(BigDecimal money) {System.out.printf("支付宝支付了:%.2f元%n", money);}@Overridepublic void refund(BigDecimal money) {System.out.printf("支付宝申请退款:%.2f元", money);}@Overridepublic void refundQuery() {System.out.println("支付宝申请退款查询");}@Overridepublic void close() {System.out.println("支付宝关闭订单");}@Overridepublic void query() {System.out.println("支付宝查询订单");}
}

微信支付相关-WeChatPayStrategy

/*** @author lyon* @createTime 2018年04月25日* @Description*/
@Service("WeChatPayStrategy")
public class WeChatPayStrategy implements PayStrategy {@Overridepublic void pay(BigDecimal money) {System.out.printf("微信支付了:%.2f元%n", money);}@Overridepublic void refund(BigDecimal money) {System.out.printf("微信申请退款:%.2f元", money);}@Overridepublic void refundQuery() {System.out.println("微信申请退款查询");}@Overridepublic void close() {System.out.println("微信关闭订单");}@Overridepublic 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);}@Overridepublic void pay(BigDecimal money) {System.out.printf("建行龙支付支付了:%.2f元%n", money);}@Overridepublic void refund(BigDecimal money) {System.out.printf("建行龙支付申请退款:%.2f元", money);}@Overridepublic void refundQuery() {System.out.println("建行龙支付申请退款查询");}@Overridepublic void close() {System.out.println("建行龙支付关闭订单");}@Overridepublic 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 {@Resourceprivate PayStrategyFactory payStrategyFactory;@Testpublic 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 {@Beanpublic 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.rhkb.cn/news/78901.html

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

相关文章

【DFS】17. 电话号码的字母组合

【DFS】17. 电话号码的字母组合 Halo&#xff0c;这里是Ppeua。平时主要更新C语言&#xff0c;C&#xff0c;数据结构算法…感兴趣就关注我bua&#xff01; TOC 题目: [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rikjhVFD-1691333891079)(C:\Us…

高成本帖子——RDK X3模组快速体验载板辅助选型

转眼&#xff0c;又是一年了&#xff0c;还记得22年6月自己第一次体验X3开发板 [首发] 多方位玩转“地平线新发布AIoT开发板——旭日X3派(Sunrise x3 Pi)” 。至今还记得拿到手的新奇与兴奋&#xff0c;还记得第一次玩BPU就遇到了大坑&#xff0c;第一次发帖就把论坛搞崩。如今…

34.利用matlab解 多变量多目标规划问题(matlab程序)

1.简述 学习目标&#xff1a;适合解 多变量多目标规划问题&#xff0c;例如 收益最大&#xff0c;风险最小 主要目标法&#xff0c;线性加权法&#xff0c;权值我们可以自己设定。 收益函数是 70*x(1)66*x(2) &#xff1b; 风险函数是 0.02*x(1)^20.01*x(2)^20.04*(x…

Tcp的粘包和半包问题及解决方案

目录 粘包&#xff1a; 半包&#xff1a; 应用进程如何解读字节流&#xff1f;如何解决粘包和半包问题&#xff1f; ①&#xff1a;固定长度 ②&#xff1a;分隔符 ③&#xff1a;固定长度字段存储内容的长度信息 粘包&#xff1a; 一次接收到多个消息&#xff0c;粘包 应…

第4章 变量、作用域与内存

引言 由于js是一门只有在声明变量后才能明确类型的语言&#xff0c;并且在任意时刻都可以改变数据类型。这也引起了一些问题 原始值与引用值 原始值就是基本数据类型&#xff0c;引言值就是复杂数据类型 变量在赋值的时候。js会判断如果是原始值&#xff0c;访问时就是按值访问…

1、sparkStreaming概述

1、sparkStreaming概述 1.1 SparkStreaming是什么 它是一个可扩展&#xff0c;高吞吐具有容错性的流式计算框架 吞吐量&#xff1a;单位时间内成功传输数据的数量 之前我们接触的spark-core和spark-sql都是处理属于离线批处理任务&#xff0c;数据一般都是在固定位置上&…

python简单知识点大全

python简单知识点大全 一、变量二、字符串三、比较运算符四、随机数4.1、随机整数4.2、随机浮点数4.3、随机数重现 五、数字类型5.1、整数5.2、浮点数5.3、复数 六、数字运算七、内置函数八、布尔类型八、逻辑运算符九、短路逻辑和运算符优先级十、分支和循环10.1、if语句10.2、…

相机传感器格式与镜头光圈参数

相机靶面大小 CCD/CMOS图像传感器尺寸&#xff08;sensor format&#xff09;1/2’‘、1/3’‘、1/4’实际是多大 1英寸——靶面尺寸为宽12.7mm*高9.6mm&#xff0c;对角线16mm。 2/3英寸——靶面尺寸为宽8.8mm*高6.6mm&#xff0c;对角线11mm。 1/2英寸——靶面尺寸为宽6.…

maven安装(windows)

环境 maven&#xff1a;Apache Maven 3.5.2 jdk环境&#xff1a;jdk 1.8.0_192 系统版本&#xff1a;win10 一、安装 apache官网下载需要的版本&#xff0c;然后解压缩&#xff0c;解压路径尽量不要有空格和中文 官网下载地址 https://maven.apache.org/download.cgihttps:…

微信小程序animation动画,微信小程序animation动画无限循环播放

需求是酱紫的&#xff1a; 页面顶部的喇叭通知&#xff0c;内容不固定&#xff0c;宽度不固定&#xff0c;就是做走马灯&#xff08;轮播&#xff09;效果&#xff0c;从左到右的走马灯&#xff08;轮播&#xff09;&#xff0c;每播放一遍暂停 1500ms &#xff5e; 2000ms 刚…

ARCGIS地理配准出现的问题

第一种。已有省级行政区矢量数据&#xff0c;在网上随便找一个相同省级行政区图片&#xff0c;利用地理配准工具给图片添加坐标信息。 依次添加省级行政区选择矢量数据、浙江省图片。 此时&#xff0c;图层默认的坐标系与第一个加载进来的省级行政区选择矢量数据的坐标系一致…

【TypeScript】TS接口interface类型(三)

【TypeScript】TS接口interface类型&#xff08;三&#xff09; 【TypeScript】TS接口interface类型&#xff08;三&#xff09;一、接口类型二、实践使用2.1 常规类型2.2 设置属性只读 readonly2.3 设置索引签名2.4 设置可选属性2.5 函数类型接口 一、接口类型 TypeScript中的…

【Linux操作系统】Vim:提升你的编辑效率

Vim是一款功能强大的文本编辑器&#xff0c;它具有高度可定制性和灵活性&#xff0c;可以帮助程序员和文本编辑者提高编辑效率。本文将介绍Vim的基本使用方法、常用功能和一些实用技巧。 文章目录 1. Vim的基本使用方法&#xff1a;2. 常用功能&#xff1a;2.1 文件操作&#…

linux的目录结构和文件类型

p&#xff1a;同一台主机之间不同程序/进程间通信要用的文件 s&#xff1a;不同主机之间不同程序/进程间通信要用的文件

Vue-组件二次封装

本次对el-input进行简单封装进行演示 封装很简单&#xff0c;就给激活样式的边框(主要是功能) 本次封装主要使用到vue自带的几个对象 $attrs&#xff1a;获取绑定在组件上的所有属性$listeners: 获取绑定在组件上的所有函数方法$slots&#xff1a; 获取应用在组件内的所有插槽 …

微服务——DSL查询文档+搜索结果处理

DSL Query分类 DSL Query的基本语法 全文检索查询 常用场景 match查询 要填一个存在的字段&#xff0c;已经要检索的内容 匹配度越高排名越前&#xff0c;这里all字段包含三个字段在里面。 multi_match查询 精确查询 不分词的查询 查询语法 term查询 range查询 gte是大于等…

Python web实战之 Django 的 MVC 设计模式详解

技术栈&#xff1a;Python、Django、HTML、CSS、JavaScript。 概要 在 Web 开发中&#xff0c;MVC&#xff08;Model-View-Controller&#xff09;模式是一种非常常见的设计模式&#xff0c;它可以帮助我们更好地管理代码&#xff0c;提高代码的可维护性。今天就介绍如何使用 …

【Linux】【预】配置网络IP,挂载网络目录

【Linux】【预】配置网络IP&#xff0c;挂载网络目录 1. 配置查看IP2.配置Linux中的IP3. 串口连接开发板&#xff0c;配置 1. 配置查看IP a . 查看ipifconfig如下操作&#xff0c;其中的&#xff1a;192.168.252.140就是它的IP b . 使用xmodem 连接到虚拟机&#xff0c;最后点…

小研究 - MySQL 数据库下存储过程的综合运用研究

信息系统工程领域对数据安全的要求比较高&#xff0c;MySQL 数据库管理系统普遍应用于各种信息系统应用软件的开发之中&#xff0c;而角色与权限设计不仅关乎数据库中数据保密性的性能高低&#xff0c;也关系到用户使用数据库的最低要求。在对数据库的安全性进行设计时&#xf…

C#与C/C++交互(1)——需要了解的基础知识

【前言】 C#中用于实现调用C/C的方案是P/Invoke&#xff08;Platform Invoke&#xff09;&#xff0c;让托管代码可以调用库中的函数。类似的功能&#xff0c;JAVA中叫JNI&#xff0c;Python中叫Ctypes。 常见的代码用法如下&#xff1a; [DllImport("Test.dll", E…