行为型设计模式的一种

【DP】定义

定义了算法家族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化不会影响到使用算法的客户。

使用场景

  1. 从定义中可以看出,如果有很多种算法或者执行策略,在客户端的判断会破坏开闭原则,因此在这种情况下可以使用策略模式

类图

策略模式

类图的核心是: 使用接口封装行为(或者说是封装变化),在上下文类中调用策略的接口。

其实是对java多态的使用。

举例

图表是有维度的概念的,但是不同类型维度的处理是不一样的,比如有字段维度和时间分组维度。在拼sql时,字段维度是直接放在group by后的内容,时间分组维度要先进行时间的截取,放到group by后边的应该是对字段的截取后的内容。

比如:

要按照组织分组,那么这个是字段维度,sql中是

by pk_org```;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47

要按照年分组,那么这个是分组维度,sql中是```group by substr(time, 1, 4) ```, ```substr```是对time字段(对应的值是19位的时间2019-04-10 17:15:20)截前四位。

那么两种不同维度的处理不同,就可以使用策略模式,代码如下:
```Java
/**
* 策略接口
*/
public interface Strategy {
String getGroupByStr(String fieldName);
}
public class FieldStrategy implements Strategy {
@Override
public String getGroupByStr(String fieldName) {
return fieldName;
}
}
public class TimeGroupStrategy implements Strategy {
@Override
public String getGroupByStr(String fieldName) {
return "substr(" + fieldName + ", 1, 4)";
}
}

/**
* 使用策略的上下文类
*/
public class StrategyContext {
private Strategy strategy;
public StrategyContext(Strategy strategy) {
this.strategy = strategy;
}
public String getGroupByStr(String fieldName) {
return strategy.getGroupByStr(fieldName);
}
}

/**
* 客户端
*/
public class Main {
public static void main() {
Strategy strategy = new TimeGroupStrategy();
StrategyContext ctx = new StrategyContext(strategy);
ctx.getGroupByStr("abcd");
}
}

看完例子之后一定有两个疑问:

  1. 为什么客户端代码还是有需要区分策略类型的代码?
  2. 上下文类的作用是什么,直接调用接口不就可以了吗?

对第一个问题,客户端的判断逻辑代码是可以挪到简单工厂类,这里我们可以把他挪到上下文类中;

对第二个问题,上下文类在这个例子中只是调了一下策略接口的方法,然而在实际应用中,接口调用的前后可能需要一些处理,这些就可以在上下文类中实现,同时有选择性地向上层调用暴露方法,使代码更加灵活。

注意事项

  1. 在理解策略模式的时候应该首先明确它是行为型模式,策略类是对变化的封装;