注:设计模式系列是我对《Head First设计模式》的读后感,有条件还是建议买一本,看起来很厚,但是寓教于乐的引导式学习真是让人欲罢不能,而且你也可以把它当作一本工具书。
设计模式是很多前辈通过“血淋淋”的教训总结出来的一些设计方法,它能提高程序的健壮性和可扩展性,是一种优秀的设计思想,把它们印入脑海,在以后的开发中 就可以“条件发射”的使用。当然,如果你写个"Hello Word"也要生搬硬套一种设计模式,那我就只能呵呵了。
策略模式的概念
策略模式定义了算法族,分别封装起来,让它们之间可以相互替换。策略模式让算法的变化独立于使用算法的用户。
策略模式的类图
以《Head First设计模式》中的类图为例:
用代码去理解
这是上面类图的简略版,我去掉了QuakBehavior.java接口和它的实现类。
步骤如下:
- 新建飞行行为接口FlyBehavior.java并实现接口;
- 新建Duck抽象类,并定义如类图中的方法。
- 其中display()是每一个Duck继承类都具有的方法,所以该方法定义成abstract类型;
- 飞行行为类FlyBehavior作为Duck的一个属性,便于动态的更改飞行行为.
- 继承Duck抽象类;
- 新建FlyBehavior.java,并提供fly方法供实现类去实现
public interface FlyBehavior {
public void fly();
}
- 实现该接口
//FlyWithWings.java为可以飞的鸭子
public class FlyWithWings implements FlyBehavior {
@Override
public void fly() {
System.out.println("I can fly...");
}
}
//FlyNoWay.java为不会飞的鸭子
public class FlyNoWay implements FlyBehavior {
@Override
public void fly() {
System.out.println("I can not fly...");
}
}
- 新建Duck.java并定义相应的属性和方法
public abstract class Duck {
public Duck() {}
public FlyBehavior flyBehavior;
public abstract void display();
public void swim(){}
public void performFly()
{
flyBehavior.fly();
}
public void setFlyBehavior(FlyBehavior flyBehavior) {
this.flyBehavior = flyBehavior;
}
}
- 继承Duck
//野鸭会飞
public class MallardDuck extends Duck {
public MallardDuck ()
{
flyBehavior = new FlyWithWings();
}
@Override
public void display() {
System.out.println("I'm Mallar Duck, I can fly...");
}
}
//红头鸭也会飞
public class RedHeadDuck extends Duck {
public RedHeadDuck () {
flyBehavior = new FlyWithWings();
}
@Override
public void display() {
System.out.println("I'm Red Head Duck, I can fly...");
}
}
//模型鸭不会飞
public class RubberDuck extends Duck {
public RubberDuck () {
flyBehavior = new FlyNoWay();
}
@Override
public void display() {
System.out.println("I'm Rubber Duck, I can not fly...");
}
}
//诱饵鸭不会飞
public class DecoyDuck extends Duck {
public DecoyDuck(){
flyBehavior = new FlyNoWay();
}
@Override
public void display() {
System.out.println("I'm Decoy Duck, I can not fly...");
}
}
- 测试
//测试发现野鸭和红头鸭确实会飞,模型鸭和诱饵鸭确实不会飞
public class DuckTest {
@Test
public void testMallardDuck() {
Duck duck = new MallardDuck();
duck.performFly();
duck.display();
}
@Test
public void testRedHeadDuck() {
Duck duck = new RedHeadDuck();
duck.performFly();
duck.display();
}
@Test
public void testRubberDuck() {
Duck duck = new RubberDuck();
duck.performFly();
duck.display();
}
@Test
public void testDecoyDuck() {
Duck duck = new DecoyDuck();
duck.performFly();
duck.display();
}
}
- 调用Set方法改变诱饵鸭的飞行行为
public class DuckTest {
@Test
public void testDecoyDuck() {
Duck duck = new DecoyDuck();
duck.display();
duck.performFly();
duck.setFlyBehavior(new FlyWithWings());
duck.performFly();
}
}
输出:
I'm Decoy Duck, I can not fly...
I can not fly...
I can fly...
好了,这就是策略模式,它可以定义很多算法族(我喜欢叫它行为类),我们只需要去实现这些行为就能做到较好的可扩展性,同时也体现了Java的面向接口编程。但是他的缺点也比较明显,它会有很多的行为类,我们在使用策略模式的时候必须知道这些行为类中有哪些方法,以便能选择正确的方法。