策略模式--strategy pattern
属于行为模式--一个类的行为或者其算法可以在运行时更改(策略模式)
策略模式封装了算法或者行为的细节到单独的类中,使算法之间可以相互替换,扩展算法的同时不会影响到其他算法,即是开闭原则的体现。
使用目的:定义一系列的算法,把他们都封装起来,并且使他们可以相互替换
解决:在有多种算法相似的情况下,使用if,,else所带来的复杂和难以维护
场景:将这些算法封装成一个个类,可以任意替换
关键代码:都是实现同一个接口interface
应用实例:
- 诸葛亮的锦囊妙计,每一个锦囊就是一个妙计
- 旅行的出游方式,选择骑自行车、顺风车、自驾,每一种旅游方式都是一个策略
- 支付方式,选择支付宝、微信支付、连连支付等,每一种支付方式都是一种策略
- 条条大路同北京,任何一条大路到达北京,则这其中的任何一条大路就是一种策略
- 通过url进行爬虫,则任何url都是一种策略
- Spring中的动态代理JDK动态代理和CGLIB动态代理,任何一种代理就是一种 策略
Spring对资源访问的封装是策略模式的经典实现。
- Spring中的动态代理JDK动态代理和CGLIB动态代理,任何一种代理就是一种 策略
- spirng 使用Resource接口来抽象资源,接口中定义了一些对资源的操作,
该接口提供了更强的资源访问能力。Spring 框架本身大量使用了 Resource 接口来访问底层资源。Resource继承了InputStreamSource接口,使其可以获取资源的底层输入流。
Resource接口有一些不同的实现类,主要有:
a:UrlResource:访问网络资源的实现类。
b:ClassPathResource:访问类路径资源。
c:FileSystemResource:访问文件系统资源。
d:ServletContextResource:访问相对于
e:ServletContext路径下的资源的实现类。
f:InputStreamResource:访问输入流资源的实现类。
g:ByteArrayResource:访问字节数组资源。
实现了ResourceLoader接口的类可以获得某个Resource的实例。ApplicationContext也是该接口的子接口,因此ApplicationContext也具有加载资源的能力。
Spring中大量的使用策略模式,这里这里只说这两个例子
优点:
- 算法可以自由切换
- 避免使用多种条件判断
- 扩展性良好
缺点:
策略类会增多
所有策略都需要对外暴露
什么场景中使用???
- 如果在一个系统里有许多类,他们之间的区别仅仅在于他们的行为,那么使用策略模式可以动态地让一个对象在许多行为中选择一种
- 一个系统需要动态地在几种算法中选择一种
- 如果一个对象有很多行为,如果不使用恰当的模式,这些行为就只好使用多重的条件选择语句实现
注意事项:也不是策略模式就是个万能,如果当系统的策略模式多余四个,就需要考虑使用混合模式,解决策略模式的膨胀问题。
基于上面的这些废话描述,咱们还是用代码来说话,就想你怎么某个人是不是SX,最好的方式就是使用代码来证明他是不是SX。
我们就基于上面提到过的支付方式来写一下代码:
AliPay.java代码
JDPay.java代码
UnionPay.java代码
Wecaht.java代码
package com.tian.pattern.strategy;
/**
* 订单信息
*
* @Author tianweichang
* @Date 2018-08-10 10:54
**/
public class Order {
/**
* 订单号
*/
private String uid;
/**
* 用户号
*/
private int userId;
/**
* 支付金额
*/
private double amount;
//这个参数,完全可以用Payment这个接口来代替
//为什么?
//完美地解决了switch的过程,不需要在代码逻辑中写switch了
//更不需要写if else if
public PayState pay(PayType payType) {
return payType.get().pay(this.uid, this.amount);
}
public Order() {
}
public Order(String uid, int userId, double amount) {
this.uid = uid;
this.userId = userId;
this.amount = amount;
}
public String getUid() {
return uid;
}
public void setUid(String uid) {
this.uid = uid;
}
public int getUserId() {
return userId;
}
public void setUserId(int userId) {
this.userId = userId;
}
public double getAmount() {
return amount;
}
public void setAmount(double amount) {
this.amount = amount;
}
}
package com.tian.pattern.strategy;
/**
* 支付完成后的状态
*
* @Author tianweichang
* @Date 2018-08-10 10:56
**/
public class PayState {
/**
* 返回码
*/
private int code;
/**
* 返回数据
*/
private Object data;
/**
* 返回提示
*/
private String msg;
public PayState(int code, String msg, Object data) {
this.code = code;
this.data = data;
this.msg = msg;
}
@Override
public String toString() {
return ("支付状态:[" + code + "]," + msg + ",交易详情:" + data);
}
}
运行结果:
总结:
- 客户端只要选择某种支付方式就行了,至于是怎么支付的不需要
- 旅游出行你只要选择你要使用的交通方式就可以了。
- 去北京你只要选择你走的大路就可以了,
- .....