跟着《重构》学设计模式-策略模式Strategy

任何一个傻瓜都能写出计算机可以理解的代码。唯有写出人类容易理解的代码,才是优秀的程序员

故事起因

最近在工作上遇到一些问题,包括算法设计问题,更多的是代码复杂,改动难,没有测试。因此读读书解解惑,开始阅读《重构》,之前读过一部分,一忙就给忘记了!

现在读到了3.11,但是受益匪浅!书中提到很多重构手法,设计模式等,也因此慢慢捡捡这些工具,希望能帮助自己写出好代码:易于阅读与修改。

正如《重构》所说:任何一个傻瓜都能写出计算机可以理解的代码。唯有写出人类容易理解的代码,才是优秀的程序员

策略模式讲解

定义与UML图

策略模式被划分到设计模式中的“行为模式”版块。Gof中的策略模式的定义:定义一系列的算法,把它们一个个封装起来,并且使它们可相互替换。在《Head First设计模式中》定义为:策略模式定义了算法族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化独立于使用算法的客户。

策略模式的UML图可以表述为如下形式(差不多是毕业N年后第一次绘制UML,,如有错误,多多指正)

image-20220723105251547

适用性

相关类仅仅是行为有异;算法存在多种变体;算法适用客户不应该知道的数据;一个类定义了多种行为,并且这些行为在这个类的操作中以多个条件语句的形式出现。

优缺点

优点

  1. 析取算法中的公共功能;
  2. 一个替代继承的方法:原本也可以通过将Context类生成多个子类的方式来实现多种算法,但是这将算法的实现与Context类混合起来,难以扩展。
  3. 消除条件语句:特别是switch-case语句
  4. 可以选择不同的实现方式

缺点

  1. 客户,即Context必须了解不同的Strategy的区别
  2. 通信开销:需要在Context与Strategy之间传值
  3. 增加了对象的数目;

其他书籍中对策略模式的补充

在《Head First设计模式》一书中,第一章就是介绍策略模式,提到了两个设计原则:

代码实现

在《Head First设计模式》中,作者举了一个实现鸭子Duck类的重构过程,原本Duck类是个包含具体行为实现fly()quack()具体行为的超类,但是后来发现,可能出现的橡皮鸭,机器鸭可能并不能非和叫,或者有其他行为,从而造成程序不易修改,因此作者使用策略模式,将原本的fly()和quack()抽象为Duck的属性以及接口:FlyBehavior,QuackBehavior,这样就可以给不同类型的鸭子指定飞行行为和嘎嘎叫的行为。

在《设计模式之禅》中,作者举了三国诸葛亮给赵云三个锦囊的例子,锦囊是一个含有妙计的类,而妙计是接口,而具体妙计则是接口的的具体实现,如“找乔国老帮忙”之类的。而赵云作为客户端使用者,直接使用的是锦囊。

在《图解设计模式》中,作者举了一个猜拳的例子,出圈算法:一个简单的算法+一个复杂的算法。

下面是《设计模式之禅》中的例子:

首先是接口:锦囊妙计

1
2
3
4
5
6
7
8
9
10
11
package com.strategy;

/**
* 首先定一个策略接口,这是诸葛亮老人家给赵云的三个锦囊妙计的接口
*/
public interface IStrategy {
/**
* 每个锦囊妙计都是一个可执行的算法
*/
public void operate();
}

然后是锦囊妙计的一个具体实现:

1
2
3
4
5
6
7
8
9
10
11
12
package com.strategy;

/**
* 找乔国老帮忙,使孙权不能杀刘备
*/
public class BackDoor implements IStrategy{

@Override
public void operate() {
System.out.println("找乔国老帮忙,让吴国太给孙权施加压力");
}
}

锦囊,锦囊中具体的妙计可以等到使用的时候指定:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package com.strategy;

/**
* @create 2022/7/22 16:09
* 计谋有了,那还要有锦囊
*/
public class Context {

//构造函数,你要使用那个妙计
private IStrategy strategy;

public Context(IStrategy strategy) {
this.strategy = strategy;
}

//使用计谋了,看我出招了
public void operate() {
this.strategy.operate();
}
}

赵云作为使用人,打开锦囊:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package com.strategy;

/**
* @create 2022/7/22 16:10
*/
public class Zhaoyun {

public static void main(String[] args) {
Context context;
//刚刚到吴国的时候拆第一个
System.out.println("-----------刚刚到吴国的时候拆第一个-------------");
context = new Context(new BackDoor()); // 拿到妙计
context.operate(); //拆开执行
System.out.println("\n\n\n\n\n\n\n\n");
}
}

书籍总结

就《策略模式》而言,在《设计模式Gof》《Head First设计模式》《设计模式之禅》《图解设计模式》这几本书来说,

《设计模式Gof》是讲的最明白的,其他书籍和该书有十分明显的差距。

其次是《Head First设计模式》,故事很恰当,举得例子很吊动人思考,对策略模式针对行为这一点讲解很透彻。

再其次是《设计模式之禅》吧,书籍很直接,例子简单明了。

再其次是《图解设计模式》,最不理解的是为什么要在将设计模式的书籍中配置一个很复杂的算法例子,要用半页甚至一页内容来讲述具体的算法实现,很容易分散读者精力,设计模式没搞懂,算法也没搞懂的尴尬境地。

注:《设计模式Gof》指的是《设计模式:可复用面向对象软件的基础》一书。