一句话总结
我有选择恐惧症 你别让我一个一个挑 我给你说需求 你帮我挑好选择恐惧症
选择恐惧症
选择恐惧症 说明了能选择的不止一个 (对应的策略不止一个)
每一个策略对应一个类
我给你说需求
这个地方我刚开始也不理解 刚开始学习的时候就知道需要那个策略直接NEW 就行了
我怎么知道该New 那一个 难道要if else 判断 如果是这样 那还用啥策略模式?
这个时候你会想到 就算 判断 是不是有个判断的依据 如 下图 这里的paymentType
不就是我要的需求吗 ?
我给你个paymentType 你给我个类不就行了
if ("支付宝".equals(paymentType)) {
} else if ("微信".equals(paymentType)) {
}
你帮我挑好
这样一分析是不是策略模式的主要角色都出来了。这里的你 该如何定义类?
上文提到的一对一的关系是不是想到了 map (还有人用枚举类)
如果你是spring的项目 也可以用applicationContext 获取不同的bean对象(下面会有案例)
抽象策略(Strategy)类:定义了一个公共接口,各种不同的算法以不同的方式实现这个接口,环境角色使用这个接口调用不同的算法,一般使用接口或抽象类实现。
具体策略(Concrete Strategy)类:(上文中的具体的选择)实现了抽象策略定义的接口,提供具体的算法实现。
环境(Context)类:(上文中的你)持有一个策略类的引用,最终给客户端调用。
细心的小伙伴会发现 这和状态模式类图很像如下图
这不是像简直一摸一样 这里先不讨论他俩的区别 详细的看https://www.runoob.com/w3cnote/state-vs-strategy.html
抽象策略(Strategy)类
public interface ImperialConcubine {
void exhibition();//妃子展示才艺
}
具体策略(Concrete Strategy)类
public class Figure implements ImperialConcubine {
private String name;
private String characteristic;
public Figure(String name, String characteristic) {
this.name = name;
this.characteristic = characteristic;
}
@Override
public void exhibition() {
System.out.println(this.name + "低头不见脚尖");
}
}
public class Hight implements ImperialConcubine{
private String name;
private String characteristic;
public Hight(String name, String characteristic) {
this.name = name;
this.characteristic = characteristic;
}
@Override
public void exhibition() {
System.out.println(this.name+"飞檐走壁,");
}
}
public class Pretty implements ImperialConcubine {
private String name;
private String characteristic;
public Pretty(String name, String characteristic) {
this.name = name;
this.characteristic = characteristic;
}
@Override
public void exhibition() {
System.out.println(this.name+"一双丹凤三角眼两弯柳叶吊梢眉");
}
}
环境(Context)类
import java.util.HashMap;
public class eunuch {
private HashMap hashMap = new HashMap();
public eunuch() {
hashMap.put("hight", new Hight("杨胜男", "个子高"));
hashMap.put("figure", new Figure("鱼幼微", "身材好"));
hashMap.put("pretty", new Pretty("花仙子", "漂亮"));
}
public ImperialConcubine getImperialConcubine(String type) {
return this.hashMap.get(type);
}
}
客户端调用
public class emperor {
public static void main(String[] args) {
eunuch eunuch = new eunuch();
ImperialConcubine pretty = eunuch.getImperialConcubine("pretty");
pretty.exhibition();
ImperialConcubine figure = eunuch.getImperialConcubine("figure");
figure.exhibition();
}
}
输出
花仙子一双丹凤三角眼两弯柳叶吊梢眉 鱼幼微低头不见脚尖
只是为了更好的让人理解 以上例子仅供参考
策略模式之付款spring版本1、定义策略接口
定义一个策略接口,所有支付方式的接口。
public interface IPayment {
PayResult pay(Order order);
}
订单信息类:
@Data
public class Order {
private int amount;
private String paymentType;
}
返回结果类:
@Data
@AllArgsConstructor
public class PayResult {
private String result;
}
2、定义各种策略
定义各种支付策略,微信支付、支付宝、云闪付等支付实现类都实现这个接口。
微信支付实现
@Service("WechatPay")
public class WechatPay implements IPayment {
@Override
public PayResult pay(Order order) {
return new PayResult("微信支付成功");
}
}
支付宝实现:
@Service("Alipay")
public class Alipay implements IPayment {
@Override
public PayResult pay(Order order) {
return new PayResult("支付宝支付成功");
}
}
云闪付实现:
@Service("UnionPay")
public class UnionPay implements IPayment {
@Override
public PayResult pay(Order order) {
return new PayResult("云闪付支付成功");
}
}
这里我把所有支付方式类都用 @Service 注解生成 Bean 放入 Spring Bean 容器中了,在使用策略的时候就不用 new 支付对象了,可以直接使用 Bean,这样更贴近业务。Spring 基础教程就不介绍了
3、使用策略
有的文章使用了枚举、HashMap 的方式来根据策略名称映射策略实现类 ,这样是没有问题,但在使用了 Spring 框架的项目还是有点多此一举,完全可以发挥 Spring 框架的优势,使用 Bean 名称就能找到对应的策略实现类了。
参考示例代码如下:
@RestController
public class PayService {
@Autowired
private ApplicationContext applicationContext;
@RequestMapping("/pay")
public PayResult pay(@RequestParam("amount") int amount,
@RequestParam("paymentType") String paymentType) {
Order order = new Order();
order.setAmount(amount);
order.setPaymentType(paymentType);
if ("支付宝".equals(paymentType)) {
} else if ("微信".equals(paymentType)) {
}
// 根据支付类型获取对应的策略 bean
IPayment payment = applicationContext.getBean(order.getPaymentType(), IPayment.class);
// 开始支付
PayResult payResult = payment.pay(order);
return payResult;
}
}
看示例代码,我并没有像策略模式结构图中那样新建一个 Context 类持有策略接口,那是标准的策略模式,其实道理是一样的,关键是怎么施放策略。
测试一下:
http://localhost:8080/pay?amount=8800&paymentType=WechatPay
5.效果
优点:
1)提供了对开闭原则的完美支持,用户可以在不修改原有系统的基础上选择算法或行为,也可以灵活地增加新的算法或行为
2)提供了管理相关的算法族的办法
3)提供了一种可以替换继承关系的办法,可以避免多重条件选择语句
4)提供了一种算法的复用机制,不同的环境类可以方便地复用策略类
缺点:
1)客户端必须知道所有的策略类,并自行决定使用哪一个策略类
2)将造成系统产生很多具体策略类
3)无法同时在客户端使用多个策略类



