Base Station

策略模式(Strategy Pettern)

Head First学习笔记(一)

字数统计: 1.9k阅读时长: 8 min
2017/02/04

前言

今年的读书计划正式开张了,其实过年的时候就把书单中的《了不起的盖茨比》给阅读完了,但是看完如猪八戒吃人参果——不知啥滋味。只知道大概的故事情节,书中华丽的词藻、作品的艺术和主题并不能完全体会,更别说写一些阅读后的观感了。抽空肯定是要重新阅读几遍的,所以就不把它当作已读书籍了。

正式的阅读是从今天开始了,准备学习技术方面的书籍,但也先来点轻松的,就是这本《Head First 设计模式》。之前看过《Head First Java》书中内容通俗易懂,生动有趣是本入门的好书,设计模式呢是和那本书一起买的,买了也有些时候了,但是从学校到工作都是各种地方吃灰的角色,一直不能静下心来实践,感到十分羞愧。工作中也用到和阅读到各种设计模式却一直没有正确的认识,呈现在赶紧捡起来。

正文

设计模式是一种反复使用、多数人知晓、经过分类编目、代码设计的总结。它告诉我们如何组织类和对象以解决某种问题。而且采纳这些设计模式并使它们适合我们特定的应用,是我们责无旁贷的事。

设计原则

虽然之前并没有系统的学习设计模式,但对设计模式的六大设计原则还是略有耳闻的。不过本书目前不知道出于什么原因没有去介绍它,而是自己组织语言目前也就不得而知了,咱还是按书上的通俗易懂的先来。

  • 找出应用中可能需要变化之处,把它们独立出来,不要和那些不需要变化的代码混在一起。
  • 针对接口编程,而不是针对实现编程。
  • 多用组合,少用继承。

实现策略模式

我们通过java代码来实现策略模式。

现在公司有一种产品——Bird(是的,你没看错,我们的产品就是鸟!),这只鸟目前的功能是walk()display。我们还开设了两个子产品乌鸦和麻雀,如图:

1
2
3
4
5
6
graph TB;
Bird["Bird<br> <br> <br>display()<br> <br>walk()"]
Bird --> crow["crow<br> <br>display() //外观是黑色"]
Bird --> sparrow["sparrow<br> <br>display() //外观是黄色"]
style Bird fill:#FFFACD;

今年,公司的竞争压力加剧,公司主管认为是该创新的时候了,他们需要在下一次股东会议上展示一些”真正”让人印象深刻的东西来振奋人心了,于是我们决定让鸟能飞!

小明拍胸脯保证一周就可以完成,他想他只要在**Bird类中加上fly()方法,这样所有鸟类就都会飞了**:

1
2
3
4
5
graph TB;
Bird["Bird<br> <br> <br>display()<br> <br>walk() <br> <br> fly() //👈小明加上的"]
Bird --> crow["crow<br> <br>display() //外观是黑色"]
Bird --> sparrow["sparrow<br> <br>display() //外观是黄色"]
style Bird fill:#FFFACD;

小明觉得天衣无缝,但是在股东会议上的展示上主管发现有很多橡胶鸟也在飞,主管让小明尽快的解决问题,不然就准备去逛前程无忧吧。

小明觉得可以把橡胶鸟类中的fly()方法覆盖掉,但是以后如果加入别的鸟类又会如何?再给鸟增加一个shout的功能呢?

利用继承来提供Bird的行为,会导致:

  • 代码在多个子类中重复。
  • 很难知道所有鸟的全部行为。
  • 改变会牵一发动全身,造成其他鸟不想要的改变。
  • 运行时的行为不容易改变。

如果用接口呢?同样不行,使用接口会导致大量的重复代码,如果要稍微修改一下飞行的姿势那么每个鸟类的都要去处理。

这时候策略模式就上场了,策略模式的定义 :

1
策略模式定义了算法族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化独立与使用算法的客户。

我们将fly()shout()Bird中声明出来,并提供两个接口FlyBehaviorShoutBehavior来实现这两个方法

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
/**
* Bird
*/
public abstract class Bird {
private FlyBehavior flyBehavior;
private ShoutBehavior shoutBehavior;

public abstract void display();

public void flyPerform() {
//调用FlyBehavior的fly方法
flyBehavior.fly();
}

public void shoutPerform() {
//ShoutBehavior的shout方法
shoutBehavior.shout();
}

public void setFlyBehavior(FlyBehavior flyBehavior) {
this.flyBehavior = flyBehavior;
}

public void setShoutBehavior(ShoutBehavior shoutBehavior) {
this.shoutBehavior = shoutBehavior;
}

public void walk() {
System.err.println("I was walking...");
}
}

/**
* FlyBehavior
*/
public interface FlyBehavior {
void fly();
}

/**
* ShoutBehavior
*/
public interface ShoutBehavior {
void shout();
}

你可能要骂娘了,这不还是使用接口吗,你丫逗我?放下手里的板凳别急。我们将鸟的行为以接口的形式声明在里面,而实现则放在分开的类中,此类专门提供某行为接口的实现,这样,鸟类就不再需要知道行为的实现细节了。

针对接口编程,关键就在于多态,程序可以针对超类型编程,执行时会根据实际状况执行到真正的行为,不会被绑死在超类型的行为上。

1
2
3
4
5
graph TB;
Bird["FlyBehavior<br> <br> <br>fly()"]
Bird --> Fly["Fly<br> <br>fly(){<br> <br> // I Can Fly<br>}"]
Bird --> FlyNoWay["FlyNoWay<br> <br>fly(){<br> <br> //I Can`t Fly<br>}"]
style Bird fill:#FFFACD;

FlyBehaviorShoutBehavior的实现类我们很简单我们就只列举一个:

1
2
3
4
5
6
public class FlyNoWay implements FlyBehavior {
@Override
public void fly() {
System.err.println("I Can`t Fly");
}
}

所有都完成后,我们增加一个产品喜鹊Magpie来测试我们模式。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/**
* 喜鹊——Bird的实现类
*/
public class Magpie extends Bird {
public Magpie() {
setFlyBehavior(new Fly());
setShoutBehavior(new Shout());
}

@Override
public void display() {
System.err.println("I`m black");
}
}

我们指定了Margpie的fly()Shout的实现类,然后我们让它飞起来:

1
2
3
4
5
6
7
8
9
public class Main {

public static void main(String args[]) {
Magpie magpie=new Magpie();
magpie.display();
magpie.flyPerform();
magpie.shoutPerform();
}
}

输出为

1
2
3
I`m black
I Can Fly
G G G...

我们也可以调用seter方法来动态改变鸟的行为。

1
2
magpie.setFlyBehavior(new FlyNoWay());
magpie.flyPerform();

输出为:

1
2
3
4
I`m black
I Can Fly
G G G...
I Can`t Fly

这就是策略模式,不要怀疑。多亏这个模式,小明可以勾画他的赌城狂欢之旅了。

现在回头看看整体的布局

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
graph TB;
subgraph 封装飞行行为
FlyBehavior["FlyBehavior<br> <br> <br>fly()"]
FlyBehavior --> Fly["Fly<br> <br>fly(){<br> <br> // I Can Fly<br>}"]
FlyBehavior --> FlyNoWay["FlyNoWay<br> <br>fly(){<br> <br> //I Can`t Fly<br>}"]
style FlyBehavior fill:#FFFACD;
end
subgraph 客户
Bird["Bird<br> <br> <br>display()<br> <br>walk() <br> <br> fly()"]
Bird --> crow["crow<br> <br>display() //外观是黑色"]
Bird --> sparrow["sparrow<br> <br>display() //外观是黄色"]
style Bird fill:#FFFACD;
end
subgraph 封装叫喊行为
ShoutBehavior["ShoutBehavior<br> <br> <br>fly()"]
ShoutBehavior --> Shout["Fly<br> <br>fly(){<br> <br> // I Can Fly<br>}"]
ShoutBehavior --> NoShout["FlyNoWay<br> <br>fly(){<br> <br> //I Can`t Fly<br>}"]
style ShoutBehavior fill:#FFFACD;
end
Bird --> FlyBehavior
Bird --> ShoutBehavior
CATALOG
  1. 1. 前言
  2. 2. 正文
    1. 2.1. 设计原则
    2. 2.2. 实现策略模式