Skip to content

Commit 71bb352

Browse files
author
jiahaixin
committed
stratrgy
1 parent ef6bbf8 commit 71bb352

File tree

2 files changed

+69
-35
lines changed

2 files changed

+69
-35
lines changed

docs/.DS_Store

0 Bytes
Binary file not shown.

docs/design-pattern/Strategy-Pattern.md

Lines changed: 69 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,15 @@
1414

1515
## 定义
1616

17-
**策略模式**:封装可以互换的行为,并使用委托来决定要使用哪一个。
17+
**策略模式**(Strategy Design Pattern):封装可以互换的行为,并使用委托来决定要使用哪一个。
1818

1919
策略模式是一种**行为设计模式**, 它能让你定义一系列算法, 并将每种算法分别放入独立的类中, 以使算法的对象能够相互替换。
2020

21-
> 用人话翻译后就是:运行时我给你这个类的方法传不同的 “key”,你这个方法会执行不同的业务逻辑
21+
> 用人话翻译后就是:运行时我给你这个类的方法传不同的 “key”,你这个方法就去执行不同的业务逻辑
2222
>
23-
> 细品一下,这不就是 if else 干的事吗?
24-
23+
> 你品,你细品,这不就是 if else 干的事吗?
2524
25+
![](https://i01piccdn.sogoucdn.com/715a60dea42bf3d5)
2626

2727
先直观的看下传统的多重 `if else` 代码
2828

@@ -55,7 +55,9 @@ public String getCheckResult(String type) {
5555

5656
![](https://img03.sogoucdn.com/app/a/100520093/e18d20c94006dfe0-0381536966d1161a-7f08208216d08261f99e84e5bf306d20.jpg)
5757

58-
网上的示例很多,比如不同路线的规划、不同支付方式的选择 都是典型的 if else 问题,也都是典型的策略模式问题,我们先看下策略模式的类图~
58+
当然,策略模式的作用可不止是避免冗长的 if-else 或者 switch 分支,它还可以像模板方法模式那样提供框架的扩展点等。
59+
60+
网上的示例很多,比如不同路线的规划、不同支付方式的选择 都是典型的 if else 问题,也都是典型的策略模式问题,栗子我们待会看,先看下策略模式的类图,然后去改造多重判断~
5961

6062

6163

@@ -65,8 +67,8 @@ public String getCheckResult(String type) {
6567

6668
策略模式涉及到三个角色:
6769

68-
- **Strategy**:策略接口或者策略抽象类,并且策略执行的接口(Context 使用这个接口来调用具体的策略实现算法)
69-
- **ConcreateStrategy**实现策略接口的具体策略类
70+
- **Strategy**:策略接口或者策略抽象类,用来约束一系列的策略算法(Context 使用这个接口来调用具体的策略实现算法)
71+
- **ConcreateStrategy**具体的策略类(实现策略接口或继承抽象策略类)
7072
- **Context**:上下文类,持有具体策略类的实例,并负责调用相关的算法
7173

7274

@@ -77,7 +79,7 @@ public String getCheckResult(String type) {
7779

7880
先看看最简单的策略模式 demo:
7981

80-
1、策略接口
82+
1、策略接口(定义策略)
8183

8284
```java
8385
public interface Strategy {
@@ -125,7 +127,7 @@ public class Context {
125127
}
126128
```
127129

128-
4、客户端使用
130+
4、客户端使用(策略的使用)
129131

130132
```java
131133
public static void main(String[] args) {
@@ -134,6 +136,8 @@ public static void main(String[] args) {
134136
}
135137
```
136138

139+
> ps:这种策略的使用方式其实很死板,真正使用的时候如果还这么写,和写一大推 if-else 没什么区别,所以我们一般会结合工厂类,在运行时动态确定使用哪种策略。策略模式侧重如何选择策略、工厂模式侧重如何创建策略。
140+
137141

138142

139143
## 解析策略模式
@@ -144,19 +148,17 @@ public static void main(String[] args) {
144148
145149

146150

147-
实际上,每个策略算法具体实现的功能,就是原来在 if-else 结构中的具体实现,每个 if-else 语句都是一个平等的功能结构,可以说是兄弟关系。
151+
实际上,每个策略算法具体实现的功能,就是原来在 `if-else` 结构中的具体实现,每个 `if-else` 语句都是一个平等的功能结构,可以说是兄弟关系。
148152

149-
策略模式呢,就是把各个平等的具体实现封装到单独的策略实现类了,然后通过上下文与具体的策略类进行交互
150-
151-
所以说,策略模式只是在代码结构上的一个调整,
153+
策略模式呢,就是把各个平等的具体实现封装到单独的策略实现类了,然后通过上下文与具体的策略类进行交互。
152154

153155
**策略模式 = 实现策略接口(或抽象类)的每个策略类 + 上下文的逻辑分派**
154156

155157
![](https://cdn.jsdelivr.net/gh/Jstarfish/picBed/design-pattern/if-else.jpg)
156158

157159
> 策略模式的本质:分离算法,选择实现 ——《研磨设计模式》
158160
159-
即使用了策略模式,你该写的业务逻辑照常写,到逻辑分派的时候,只是变相的 `if-else`
161+
所以说,策略模式只是在代码结构上的一个调整,即使用了策略模式,该写的逻辑一个也少不了,到逻辑分派的时候,只是变相的 `if-else`
160162

161163
而它的优化点是抽象了出了接口,将业务逻辑封装成一个一个的实现类,任意地替换。在复杂场景(业务逻辑较多)时比直接 `if-else` 更好维护和扩展些。
162164

@@ -168,64 +170,96 @@ public static void main(String[] args) {
168170

169171
其实,策略模式中,我们可以自己定义谁来选择具体的策略算法,有两种:
170172

171-
- 客户端:当使用上下文时,由客户端选择,像我们的 demo
172-
- 上下文:客户端不用选,由上下文选
173+
- 客户端:当使用上下文时,由客户端选择,像我们上边的 demo
174+
- 上下文:客户端不用选,由上下文来选具体的策略算法,可以在构造器中指定
173175

174176

175177

176178
### 优缺点
177179

178180
#### 优点:
179181

180-
- 定义一系列算法:策略模式的功能就是定义一系列算法,实现让这些算法可以相互替换,所以为这一系列算法定义公共的接口,以约束一系列算法要实现的功能。如果这一系列算法具有公共功能,可以把策略接口实现为抽象类,把这些公共功能实现到父类
181182
- 避免多重条件语句:也就是避免大量的 `if-else`
182183
- 更好的扩展性(完全符合开闭原则):策略模式中扩展新的策略实现很容易,无需对上下文修改,只增加新的策略实现类就可以
183184

184185
#### 缺点:
185186

186-
- 客户必须了解每种策略的不同
187+
- 客户必须了解每种策略的不同(这个可以通过 IOC、依赖注入的方式解决)
187188
- 增加了对象数:每个具体策略都封装成了类,可能备选的策略会很多
188-
- 只适合扁平的算法结构:
189+
- 只适合扁平的算法结构:策略模式的一系列算法是平等的,也就是在运行时刻只有一个算法会被使用,这就限制了算法使用的层级,不能嵌套使用
190+
189191

190192

193+
### 思考
191194

192-
### 适用场景
195+
实际使用中,往往不会只是单一的某个设计模式的套用,一般都会混合使用,而且模式之间的结合也是没有定势的,要具体问题具体分析。
193196

194-
> 策略模式的本质:分离算法,选择实现
197+
策略模式往往会结合其他模式一起使用,比如工厂、模板等,具体使用需要结合自己的业务。
195198

196-
- 当你想使用对象中各种不同的算法变体, 并希望能在运行时切换算法时,可使用策略模式
199+
切记,不要为了使用设计模式而强行模式,不要把简单问题复杂化
197200

198-
- 当你有许多仅在执行某些行为时略有不同的相似类时(它们之间的区别仅在于它们的行为),使用策略模式可以动态地让一个对象在许多行为中选择一种行为
201+
策略模式也不是专为消除 if-else 而生的,不要和 `if-else` 划等号。它体现了“对修改关闭,对扩展开放“的原则。
199202

200-
- 如果算法在上下文的逻辑中不是特别重要, 使用该模式能将类的业务逻辑与其算法实现细节隔离开来。
203+
并不是说,看到 `if-else` 就想着用策略模式去优化,业务逻辑简单,可能几个枚举,或者几个卫语句就搞定的场景,就不用非得硬套设计模式了
201204

202-
策略模式让你能将各种算法的代码、 内部数据和依赖关系与其他代码隔离开来。 不同客户端可通过一个简单接口执行算法, 并能在运行时进行切换。
203205

204-
- **当类中使用了复杂条件运算符以在同一算法的不同变体中切换时,可使用该模式**
205206

206-
- 策略模式将所有继承自同样接口的算法抽取到独立类中, 因此不再需要条件语句。 原始对象并不实现所有算法的变体, 而是将执行工作委派给其中的一个独立算法对象。
207+
## 策略模式在 JDK 中的应用
207208

209+
在 JDK 中,Comparator 比较器是一个策略接口,我们常用的 `compare()` 方法就是一个具体的策略实现,用于定义排序规则。
208210

211+
```java
212+
public interface Comparator<T> {
213+
int compare(T o1, T o2);
214+
//......
215+
}
216+
```
209217

210-
实际使用中,往往不会只是单一的某个设计模式的套用,一般都会混合使用,而且模式之间的结合也是没有定势的,要具体问题具体分析
218+
当我们想自定义排序规则的时候,就可以实现 `Comparator`
211219

212-
策略模式往往会结合其他模式一起使用,
220+
这时候我们重写了接口中的 `compare()` 方法,就是具体的策略类(只不过这里可能是内部类)。当我们在调用 Arrays 的排序方法 `sort()` 时,可以用默认的排序规则,也可以用自定义的规则。
213221

214-
### 策略模式在 JDK 中的应用
222+
```java
223+
public static void main(String[] args) {
224+
Integer[] data = {4,2,7,5,1,9};
225+
Comparator<Integer> comparator = new Comparator<Integer>() {
226+
@Override
227+
public int compare(Integer o1, Integer o2) {
228+
if(o1 > o2){
229+
return 1;
230+
} else {
231+
return -1;
232+
}
233+
}
234+
};
215235

216-
#### 策略模式在 Spring 中的应用
236+
Arrays.sort(data,comparator);
237+
System.out.println(Arrays.toString(data));
238+
}
239+
```
217240

218-
https://mp.weixin.qq.com/s?__biz=MzAxODcyNjEzNQ==&mid=2247487480&idx=2&sn=461a012afd41d4e2466a9024b81b6e39&chksm=9bd0a260aca72b760e429753beb1fa12270c18b5cc6829538ccbfefcc23214fefc0aadd575c8&scene=27#wechat_redirect
241+
Arrays 的 `sort()` 方法
219242

243+
```java
244+
public static <T> void sort(T[] a, Comparator<? super T> c) {
245+
if (c == null) {
246+
sort(a);
247+
} else {
248+
if (LegacyMergeSort.userRequested)
249+
legacyMergeSort(a, c);
250+
else
251+
TimSort.sort(a, 0, a.length, c, null, 0, 0);
252+
}
253+
}
254+
```
220255

221256

222-
最后:
223257

224-
并不是说,看到if-else 就想着用策略模式去优化,业务逻辑简单,可能几个枚举,或者几个卫语句就搞定的场景,就不用非得硬套设计模式了,杀鸡焉用牛刀,是吧,可以看看参考文章第一篇
258+
还有,ThreadPoolExecutor 中的拒绝策略 RejectedExecutionHandler 也是典型的策略模式,感兴趣的也可以再看看源码。
225259

226260

227261

228-
参考与感谢:
262+
## 参考与感谢:
229263

230264
- [《用 Map + 函数式接口来实现策略模式》](https://www.cnblogs.com/keeya/p/13187727.html)
231265
- 《研磨设计模式》

0 commit comments

Comments
 (0)