策略模式

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

模拟鸭子应用

现在有一个系统可以生产各种类型的鸭子,这些鸭子都会游泳、呱呱叫,但每个鸭子的外观都略有不同。
目前次系统设计了一个鸭子超类,并且让各种鸭子继承次超类。

1
2
3
4
5
6
7
8
9
10
11
12
13
// 鸭子超类
public abstract class Duck {

void quack() {
System.out.println("呱呱叫");
}

void swim() {
System.out.println("会游泳");
}

abstract void display();
}
1
2
3
4
5
6
7
8
class MallardDuck extends Duck {

@Override
void display() {
System.out.println("野鸭");
}
}
// 各种各样的鸭子...

需求变更:让鸭子会飞

1
2
3
4
5
6
public abstract class Duck {
// 其他方法省略...
void fly() {
System.out.println("会飞");
}
}

问题:并不是所有的鸭子都会飞如橡皮鸭

解决方案:给不会飞的鸭子覆盖fly()方法

1
2
3
4
5
6
7
8
9
10
11
12
class RubberDuck extends Duck {

@Override
void display() {
System.out.println("橡皮鸭");
}

@Override
void fly() {
System.out.println("不会飞");
}
}

如果需求继续变更会怎么样?

  • 加入诱饵鸭,不会飞不会叫,只会游泳
  • 加入xx鸭,只会飞

当需求变化,加入的鸭子越来越多,鸭子的功能也越来越多,会变的怎么样?

  • 根据鸭子的种类来调整鸭子飞的行为
  • 新加入鸭子行为

当有需求变化时,会导致重复的代码越来越多,新增一个功能,要改变大量类。

思考为什么会出现这种情况?

最初设计的时候没能找到变化点,并且将变化点封装起来。

改造

飞行为接口和实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public interface FlyBehavior {
void fly();
}

public class FlyNoWay implements FlyBehavior{
@Override
public void fly() {
System.out.println("我不会飞");
}
}

public class FlyWithWings implements FlyBehavior{
@Override
public void fly() {
System.out.println("我会飞");
}
}

叫行为接口和实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public interface QuackBehavior {
void quack();
}

public class Quack implements QuackBehavior{
@Override
public void quack() {
System.out.println("咕咕叫");
}
}

public class MuteQuack implements QuackBehavior{
@Override
public void quack() {
System.out.println("不会叫");
}
}

鸭子超类和实现

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
public abstract class Duck {
FlyBehavior flyBehavior;

QuackBehavior quackBehavior;

public Duck() {}

public abstract void display();

public void swim() {
System.out.println("鸭子都会游泳");
}

public void performFly() {
flyBehavior.fly();
}

public void performQuack() {
quackBehavior.quack();
}
// getter setter...
}

public class MallarDuck extends Duck{

public MallarDuck() {
this.flyBehavior = new FlyWithWings();
this.quackBehavior = new MuteQuack();
}

@Override
public void display() {
System.out.println("绿头鸭");
}
}

运行

1
2
3
4
5
6
7
8
9
public class App {
public static void main(String[] args) {
Duck mallard = new MallarDuck();
mallard.performFly();
mallard.performQuack();
mallard.display();
mallard.swim();
}
}

设计原则

  • 多用组合,少用继承。
  • 针对接口编程,而不是针对实现 编程。