设计模式 - 策略模式

设计模式也是在工作中才会发现其作用。在规模较小的情况下,往往随意写来比较方便快速,可是对于大型的系统来说,各个部分用上合适的设计模式可以更好的维护系统,也更加的清晰。最近看了看一些web框架的源码,比如用的最多的Spring,一个web请求就会经过很多层的处理,其中用了很多设计模式,如果不了解则很难理解为什么要如此设计。所以还是从基础的开始吧。

下面说的是一个比较简单的 策略模式

策略模式的定义:一个类的行为或其算法可以在运行时更改。这种类型的设计模式属于行为型模式。

不像其他模式的定义显得很绕,策略模式的含义一看就比较清晰了。行为或者算法在运行时可以更改,首先能想到的便是通过面向对象中的多态来达到目的。在运行的过程中,根据需要动态的设定对象,对于调用者来说只要持有他们共同的接口就行了。正好,策略模式也正是这样。

看下面的例子(来自《Head First 设计模式》):

对于一只鸭子,它有飞和叫的行为,但是不同的鸭子表现出来的不一样。如果在一个类中表示所有的鸭子,则要进行各种判断,所以使用策略模式,将能够根据需要表现出不同鸭子的性质。

首先定义它的飞的行为:

1
2
3
4
5
package io.lovs.learn.design.strategy;

public interface FlyBehavior {
void fly();
}

再定义叫的行为:

1
2
3
4
5
package io.lovs.learn.design.strategy;

public interface QuackBehavior {
void quack();
}

对两种行为添加不同的实现,首先是飞的行为:

1
2
3
4
5
6
7
8
package io.lovs.learn.design.strategy;

public class FlyWithWings implements FlyBehavior {
@Override
public void fly() {
System.out.println("start fly");
}
}
1
2
3
4
5
6
7
8
package io.lovs.learn.design.strategy;

public class FlyNoWay implements FlyBehavior {
@Override
public void fly() {
System.out.println("I can't fly");
}
}

上面分别定义了一个飞和不回飞的行为

然后是叫的行为:

1
2
3
4
5
6
7
8
package io.lovs.learn.design.strategy;

public class Squeak implements QuackBehavior {
@Override
public void quack() {
System.out.println("Squeak");
}
}
1
2
3
4
5
6
7
8
package io.lovs.learn.design.strategy;

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

这里定义了叫和不叫的行为

然后定义一只抽象的鸭子,它将包含鸭子的基本属性,具体的鸭子可继承它然后实现各自的特点。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package io.lovs.learn.design.strategy;

public abstract class Duck {

FlyBehavior flyBehavior;
QuackBehavior quackBehavior;

public void display() {
System.out.println("It's a duck");
}

abstract void fly();
abstract void quack();

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

public void setQuackBehavior(QuackBehavior quackBehavior) {
this.quackBehavior = quackBehavior;
}
}

再来实现一只具体的鸭子

1
2
3
4
5
6
7
8
9
10
11
12
13
package io.lovs.learn.design.strategy;

public class RealDuck extends Duck {
@Override
void fly() {
flyBehavior.fly();
}

@Override
void quack() {
quackBehavior.quack();
}
}

具体的某只鸭子继承了基本的鸭子的属性,在这里,主要实现了各自的叫和飞的行为。从抽象鸭子的定义中可以看到,它不直接实现飞和叫的功能,而是持有了飞和叫的接口,通过设置具体的飞与叫的类来实现该动作,达到了动态改变的效果,如果需要改变其行为,只要重新设置新的属性就好了。

测试类:

1
2
3
4
5
6
7
8
9
10
11
12
package io.lovs.learn.design.strategy;

public class Test {
public static void main(String[] args) {
Duck duck = new RealDuck();
duck.setFlyBehavior(new FlyNoWay());
duck.setQuackBehavior(new Quack());
duck.display();
duck.fly();
duck.quack();
}
}

输出:

1
2
3
It's a duck
I can't fly
quack

策略模式相对简单,在书中也作为第一个讲解的内容。如果自己想象平时做的东西,在某些地方已经不经意中到了这样的模式。所以模式来源于实践当中,而单独看这些模式也没有意义,要在实际项目中真正的运用才算是发挥了真正的作用。这个模式就到这里吧。