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
8385public interface Strategy {
@@ -125,7 +127,7 @@ public class Context {
125127}
126128```
127129
128- 4、客户端使用
130+ 4、客户端使用(策略的使用)
129131
130132``` java
131133public 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