也叫政策模式(Policy Pattern)
对象有某个行为,但是在不同的场景中,该行为有不同的实现算法。
如每个人都要“交个人所得税”,但是“在美国交个人所得税”和“在中国交个人所得税”就有不同算税方法。
Define a family of algorithms,encapsulate each one,and make them interchangeable. 定义一组算法,将每个算法都封装起来,并且使它们之间可互换。
每种算法可以根据当前场景相互替换,从而使算法的变化独立于使用它们的客户端(即算法的调用者)。
常见 if/else 结构。
行为型。
在运行时(非编译时)改变软件的算法行为。
定义一个通用问题,使用不同算法实现,然后将这些算法都封装在统一接口。
策略模式使用的就是OOP的继承和多态。
即上下文角色,起承上启下的封装作用。屏蔽高层模块对策略&算法的直接访问,封装可能存在的变化。
持有一个策路类的引用,最终给客户端调用。
策略&算法家族的抽象,通常为接口,定义每个策略或算法必须的方法和属性。
实现抽象策略定义的接口,提供具体算法实现。
抽象策略角色:一个非常普通的接口,在项目中就是一个普通接口,定义一或多个具体算法。
一个对象,其行为有些固定不变,有些又容易变化。对于这些容易变化的行为,我们不希望将其实现绑定在对象,而希望能动态针对不同场景产生不同应对策略。 就用到策略模式,就是为应对对象中复杂多变的行为而产生的:
- 系统有很多类,而他们的区别仅在于行为不同
- 一个系统需要动态地在几种算法中选择一种
当一个类存在两个独立变化的维度,目这两个维度都需要进行扩展时 当一个系统不希望使用继承,或因多层次继承导致系统类的个数急剧增加时 当一个系统需要在构件的抽象化角色、具体化角色之间增加更多的灵活性时
- 符合OCP
- 避免使用多重条件转移语句 e.g. 省去大量 if/else、switch,降低代码耦合度
- 提高算法的保密性和安全性 只需知道策略的业务功能,而不关心内部实现
- 客户端须知所有策略类,并决定使用哪个策略类
- 产生很多策略类
前面的都是策略模式表述。
- 行为型 接收已创建好的对象实现不同行为
- 创造型 接收指令,创建符合要求的具体对象
- 若系统中某类的某行为存在多种实现方式,客户端需知使用哪个策略
- 若系统中某对象存在多种状态,不同状态下的行为又有差异,状态之间会自动转换,客户端无需关心具体状态
- 注重选择结果,只有选择权(由用户自己选择已有算法)
- 关心业务流程的固定(修改某部分的逻辑,但不影响流程执行)。侧重点不是选择,你没得选,你必须这么做。你可参与某部分内容的自定义
注重命令的个数,分类相当于菜单(内容如何定义)。没有UI以前的DOC界面。
请选择以下功能:
1.开户 2.转账 3.挂失 4.退出
1:
1.信用卡 2.借记卡多态:Java语法(有些语言的语法是不支持多态的,它照样也要用来实现业务逻辑,也要使用设计模式) 策略:是一种经验的总结
促销策略接口
package com.javaedge.design.pattern.behavioral.strategy;
/**
* 促销策略接口
*
* @author JavaEdge
* @date 2019/1/16
*/
public interface PromotionStrategy {
/**
* 促销
*/
void doPromotion();
}满减策略:
package com.javaedge.design.pattern.behavioral.strategy;
/**
* 满减策略
*
* @author JavaEdge
* @date 2019/1/16
*/
public class FullOffPromotionStrategy implements PromotionStrategy {
@Override
public void doPromotion() {
System.out.println("满减促销,满200减20元");
}
}改造后的测试类:
PromotionActivity promotionActivity = null;
String promotionKey = "LIJIAN";
if (StringUtils.equals(promotionKey, "LIJIAN")) {
promotionActivity = new PromotionActivity(new MinusPromotionStrategy());
} else if (StringUtils.equals(promotionKey, "FANXIAN")) {
promotionActivity = new PromotionActivity(new CashBackPromotionStrategy());
}//...
promotionActivity.executePromotionStrategy();if/else 过多,采取策略+工厂模式结合
策略工厂:
package com.javaedge.design.pattern.behavioral.strategy;
import java.util.HashMap;
import java.util.Map;
/**
* 策略工厂
*
* @author JavaEdge
* @date 2019/1/16
*/
public class PromotionStrategyFactory {
private static Map<String, PromotionStrategy> PROMOTION_STRATEGY_MAP = new HashMap<>();
static{
PROMOTION_STRATEGY_MAP.put(PromotionKey.LIJIAN, new MinusPromotionStrategy());
PROMOTION_STRATEGY_MAP.put(PromotionKey.MANJIAN, new FullOffPromotionStrategy());
PROMOTION_STRATEGY_MAP.put(PromotionKey.FANXIAN, new CashBackPromotionStrategy());
}
private static final PromotionStrategy NON_PROMOTION = new EmptyPromotionStrategy();
/**
* 不希望外部调用
*/
private PromotionStrategyFactory() {}
public static PromotionStrategy getPromotionStrategy(String promotionKey) {
PromotionStrategy promotionStrategy = PROMOTION_STRATEGY_MAP.get(promotionKey);
return promotionStrategy == null ? NON_PROMOTION : promotionStrategy;
}
/**
* 填充 map 中的 key
*/
private interface PromotionKey {
String LIJIAN = "LIJIAN";
String FANXIAN = "FANXIAN";
String MANJIAN = "MANJIAN";
}
}最新测试类:
String promotionKey = "LIJIAN";
PromotionActivity promotionActivity = new PromotionActivity(
PromotionStrategyFactory.getPromotionStrategy(promotionKey));
promotionActivity.executePromotionStrategy();支付时,可根据实际选择不同支付方式(微信支付、支付宝、银行卡支付等),这些支付方式即是不同策略。通常看到如下实现:
Order order = 订单信息
if (payType == 微信支付) {
...
} else if (payType == 支付宝) {
支付宝支付流程
} else if (payType == 银行卡) {
银行卡支付流程
} else {
暂不支持的支付方式
}虽写着简单,但违反面向对象2个基本原则:
- 单一职责原则:一个类只有1个发生变化的原因。之后修改任何逻辑,当前方法都会被修改
- 开闭原则:对扩展开放,对修改关闭。当需要增加、减少某种支付方式(积分支付/组合支付)或增加优惠券等功能时,不可避免要修改代码
特别当 if-else 块中的代码量比较大时,后续的扩展和维护会变得非常复杂且容易出错。在阿里《Java开发手册》中,有这样的规则:超过3层的 if-else 的逻辑判断代码可以使用卫语句、策略模式、状态模式等来实现。
策略模式是解决过多 if-else(或者 switch-case) 代码块的方法之一,提高代码的可维护性、可扩展性和可读性。从策略的定义、创建和使用这三个方面以上述网购支付为示例来分别进行说明。
策略的定义 策略接口的定义,通常包含两个方法:获取策略类型的方法和处理策略业务逻辑的方法。
// 第三方支付
public interface Payment {
// 获取支付方式
PayTypeEnum getPayType();
/**
* 支付调用
*
* @param order 订单信息
* @return 响应,支付结果
*/
PayResult pay(Order order);
}策略接口的实现,每种支付类都实现了上述接口(基于接口而非实现编程),这样我们可以灵活的替换不同的支付方式。
每种支付方式的实现:
@Component
public class WxPayment implements Payment {
@Override
public PayTypeEnum getPayType() {
return PayTypeEnum.WX;
}
@Override
public PayResult pay(Order order) {
// 调用微信支付
if (成功) {
return PayResult.SUCCESS;
} else {
return PayResult.FAIL;
}
}// 支付宝支付
@Component
public class AlipayPayment implements Payment {
@Override
public PayTypeEnum getPayType() {
return PayTypeEnum.ALIPAY;
}
@Override
public PayResult pay(Order order) {
// 调用支付宝支付
if (成功) {
return PayResult.SUCCESS;
} else {
return PayResult.FAIL;
}
}
}// 银行卡支付
@Component
public class BankCardPayment implements Payment {
@Override
public PayTypeEnum getPayType() {
return PayTypeEnum.BANK_CARD;
}
@Override
public PayResult pay(Order order) {
// 调用银行卡支付
if (成功) {
return PayResult.SUCCESS;
} else {
return PayResult.FAIL;
}
}
}策略比较器:
* @param <T> the type of objects that may be compared by this comparator
*
* @author Josh Bloch
* @author Neal Gafter
* @see Comparable
* @see java.io.Serializable
* @since 1.2
*/
@FunctionalInterface
public interface Comparator<T> {
boolean equals(Object obj);
}具体策略:
如Arrays类中的 sort 方法通过传入不同比较器实现达到不同排序策略:
public final class Arrays {
public static <T> void sort(T[] a, Comparator<? super T> c) {
if (c == null) {
sort(a);
} else {
if (LegacyMergeSort.userRequested)
legacyMergeSort(a, c);
else
TimSort.sort(a, 0, a.length, c, null, 0, 0);
}
}
}类似于促销活动中有促销策略对象,在T reeMap 中也有比较器对象
public class TreeMap<K,V>
extends AbstractMap<K,V>
implements NavigableMap<K,V>, Cloneable, java.io.Serializable
{
/**
* The comparator used to maintain order in this tree map, or
* null if it uses the natural ordering of its keys.
*
* @serial
*/
@SuppressWarnings("serial") // Conditionally serializable
private final Comparator<? super K> comparator;compare 方法进步加工:
不同访问策略:
// 资源描述符的接口,该描述符从基础资源的实际类型(如文件或类路径资源)中抽象出来
// 若 InputStream 以物理形式存在,则可为每个资源打开它,但只能为某些资源返回 URL 或 File 句柄
public interface Resource extends InputStreamSource {两种 bean 初始化策略:





