学习Object Oriented(OO)也有段时间了,但一直没有学习Pattern Design方面的东西,感觉使用OO的时候完全不给力啊。So, balabala........
Sorry,扯了一点废话。
Strategy Pattern,在WikiPedia中解释为:a particularsoftware design pattern, whereby algorithms can be selected at runtime. 也就是说,Strategy Pattern在运行时能够改变算法的一种设计模式。那么,这个算法是什么呢?这里的算法,指的是Object的行为,比如一个Duck,它拥有Fly的行为,但是运行时改变算法,使其can't Fly。这就是Strategy Pattern的优势所在。当然,《Head First 设计模式》中对它也有定义:定义了算法族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化独立于使用算法的客户。
OK,我们以《Head First 设计模式》中的例子来说明。
我们要设计以下两个类,MallarDuck(绿头鸭)和RedheadDuck(红头鸭)。既然都是Duck(鸭),会OO的人都会想到--inherit(继承)。那这两种鸭子有什么共有的特性,我们可以将它们抽象出来放入一个父类Duck中呢。哦,它们都会quack,还有swim!于是,有了下面的设计:
嗯,看起来不错的样子。但是过了一天,老板(产品经理,又或者其他**,你明白的)说,我们要新的功能,MallardDuck和RedheadDuck都要有fly( )的行为!嗯,不怕,OO的好处来了。只要在Duck类中新加入fly( )行为,这下所有的子类都有fly( )的行为了,一切OK!
等等,让我想想,真的OK吗?第3天,**(who?)又说,我们仅有MallardDuck与RedheadDuck太少了,我们需要一个RubberDuck ! OK,so easy。
Hold on ! RubberDuck好像不会飞啊。但是为什么RubberDuck有fly( )这个行为!那也行,好吧,在RubberDuck中覆盖fly( )方法,但是什么也不做吧。
class RubberDuck extend Duck {
......
@override
public fly() {
// do nothing
}
......
}
看上去还成。但是如果不止增加RubberDuck呢,还有ModelDuck, 以及**Duck, balabala........那不是每个类都要覆盖fly( )方法?你怎么知道只有fly( )方法。要是**Duck不会swim呢(我们假设有这样一种Duck)?OMG,我的OO呢,说好的方便呢?
嘿,谁说没有好方法。且看:
这下,谁看要什么方法就让它有吧,想要fly( )方法,就实现Flyable这个接口;想要quack方法,就实现Quackable接口。Oh, No ! 这不是N多代码重复吗!MallardDuck与RedheadDuck的fly( )方法是一样的啊,说好的代码复用呢?
等等,好像灵感又来了!代码复用?参考Duck类的做法不就行了!
Oh, 终于告一段落了,这样就可以了!再等等!什么,还有?!学习OO的时候,前人都告诫说:少用继承,多用组合。似乎继承过多了。。。还是多重的。。。那再修改!
这么修改,还增加了一个功能:运行时可以替换Object的行为啊,组合果然是个good choice !
其实,最后一个版本就是刚开始就提到的Strategy Pattern, 真是“千呼万唤始出来”啊。
另外,附上最终的Java代码,让我们更好的理解它。
Duck.java:
// Duck.java
public abstract class Duck {
FlyBehavior flyBehavior;
QuackBehavior quackBehavior;
public Duck() {
}
public abstract void display();
public void performFly(){
flyBehavior.fly();
}
public void performQuack() {
quackBehavior.quack();
}
public void swim() {
System.out.println("All ducks float, even decoys!");
}
public void setFlyBehavior(FlyBehavior fb) {
flyBehavior = fb;
}
public void setQuackBehavior(QuackBehavior qb) {
quackBehavior = qb;
}
}
FlyBehavior.java:
// FlyBehavio.java
public interface FlyBehavior {
public void fly();
}
FlyWithWings.java:
// FlyWithWings
public class FlyWithWings implements FlyBehavior {
@Override
public void fly() {
// TODO Auto-generated method stub
System.out.println("I'am flying!");
}
}
FlyNoWay.java:
// FlyNoWay.java
public class FlyNoWay implements FlyBehavior {
@Override
public void fly() {
// TODO Auto-generated method stub
System.out.println("I can't fly!");
}
}
FlyRockedPowered.java:
// FlyRockedPowered
public class FlyRockedPowered implements FlyBehavior {
@Override
public void fly() {
// TODO Auto-generated method stub
System.out.println("I' am flying with a rocked!");
}
}
QuackBehavior.java:
// QuackBehavior.java
public interface QuackBehavior {
public void quack();
}
Quack.java
// Quack.java
public class Quack implements QuackBehavior {
@Override
public void quack() {
// TODO Auto-generated method stub
System.out.println("Quack");
}
}
MuteQuack.java
// QuackBehavior.java
public class MuteQuack implements QuackBehavior {
@Override
public void quack() {
// TODO Auto-generated method stub
System.out.println("<< Silence >>");
}
}
Squeak.java
// Squeak.java
public class Squeak implements QuackBehavior {
@Override
public void quack() {
// TODO Auto-generated method stub
System.out.println("Squeak");
}
}
MallardDuck.java:
// MallardDuck
public class MallardDuck extends Duck {
public MallardDuck() {
quackBehavior = new Quack();
flyBehavior = new FlyWithWings();
}
@Override
public void display() {
// TODO Auto-generated method stub
System.out.println("I'm a real Mallard duck");
}
}
ModelDuck.java:
// ModelDuck
public class ModelDuck extends Duck {
ModelDuck() {
flyBehavior = new FlyNoWay();
quackBehavior = new Quack();
}
@Override
public void display() {
// TODO Auto-generated method stub
System.out.println("I'm a model duck!");
}
}
Test.java
// Test.java
public class Test {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
Duck mallard = new MallardDuck();
mallard.performFly();
mallard.performQuack();
System.out.println("------------------- now, change the duck! --------------------");
Duck model = new ModelDuck();
model.performFly();
System.out.println("------------------- now, set rocked on the model! --------------------");
model.setFlyBehavior(new FlyRockedPowered());
model.performFly();
}
}