设计模式(一)会飞的鸭子(策略模式)
938字约3分钟
设计模式
2018-04-22
设计原则:
多用组合(composition),少用继承。
鸭子类
首先我们有一个鸭子类
public abstract class duck{
quack();
swim();
display();
}
然后具体是哪种鸭子,只要去继承这个鸭子类就好了。
比如 MallardDuck 重写 display()
方法,它就是绿头鸭。
public class MallardDuck extends duck{
@Overwrite
display(){
//... green
}
}
现在,我们得让鸭子能飞
public abstract class duck{
quack();
swim();
display();
fly(); // it fly
}
然后你会惊奇地发现,橡皮鸭(RubberDuck)居然飞起来了。这不科学!
可能的解决方案
- 重写:可以重写橡皮鸭(RubberDuck)的 fly 方法,变成什么都不做。但是这样假若我们又添加了诱饵鸭(DecoyDuck),不会 fly 也不会 quack , 我们又要去重写。显然也很麻烦。
- 接口:可以把 fly 抽象成一个 flyable 接口,让会飞的鸭子去实现这接口。但是我们有 48 个 鸭子子类,都要去实现一遍吗?
显然,继承或重写不能解决问题,因为鸭子的行为在子类里不断地改变,并且让所有的子类都有这些行为是不切当的。 抽象出 flyable 接口 和 quackable 接口,让具备这些功能的鸭子子类去实现这些接口,要写很多重复代码,无法复用。
设计原则:
找出应用中可能需要变化的地方,把它们独立出来,不要和那些不需要变化的代码混在一起。
解决方案
既然 fly 和 quack 会随着鸭子的不同而改变,那么不妨把这两个行为抽出来,新建成 鸭子行为 类。然后在鸭子类中包含设定行为的方法。
关键点:
- 新建鸭子行为类
- 在鸭子类中添加设定行为的方法
这样一来,我们 new 一个 绿头鸭(MallardDuck)的时候,就能给它指定特定的 fly 行为 和 quack 行为。
设计原则:
针对接口编程,而不是针对实现编程。
具体实施
定义FlyBehavior
接口,里面有一个 fly()
方法。FlyWithWings
类实现了这个接口,表示用翅膀飞,FlyNoWay
类也实现这个接口,表示不会飞,FlyWithRocket
类也实现这个接口,表示用火箭发动机飞。
同理,定义QuackBehavior
接口,然后有几个不同的实现类。比如Quack()
表示呱呱叫,MuteQuack()
表示不会叫。
现在,鸭子类是这样的
public abstract class duck{
QuackBehavior quackBehavior;
FlyBehavior flyBehavior;
public void performQuack(){
quackBehavior.quack();
}
public void performFly(){
flyBehavior.fly();
}
//设定鸭子的飞行行为
public void setFlyBehavior(FlyBehavior fb){
flyBehavior = fb;
}
//设定鸭子的叫声行为
public void setQuackBehavior(QuackBehavior qb){
quackBehavior = qb;
}
//... more
}
现在,橡皮鸭(RubberDuck)类看起来是这样的
public class RubberDuck extends Duck {
public RubberDuck(){
//一开始,橡皮鸭并不会飞
flyBehavior = new FlyNoWay();
QuackBehavior = new Quack();
}
}
测试类
public static void main(String[] args){
// 创建一个橡皮鸭实例,此时调用橡皮鸭的构造方法
//也就是为橡皮鸭设定了不会飞,呱呱叫
Duck rubber = new RubberDuck();
// 飞一下看看(结果:不会飞)
rubber.performFly();
//设定新的飞行行为
rubber.setFlyBehavior(new FlyWithRocket());
// 再飞一下看看(结果:火箭动力飞)
rubber.performFly();
}
至此,我们的鸭子就飞起来了。
所谓组合,就是鸭子类和鸭子行为类的组合。实例化一个鸭子的时候,给它组装上对应的行为。
以上,其实就是设计模式中的 策略模式(Strategy Pattern) 了。策略模式提供了多种实体类和行为类,使用者需要哪种实体和哪种行为,可以自己去组装。
参考:
- 《Head First 设计模式》