使用模式最好的方式是:“把模式装进脑子里,然后在你的设计和已有的应用中,寻找何处可以使用它们。”
书中例子:
有一套模拟鸭子的游戏。游戏中会出现各种鸭子,一边游泳戏水,一边呱呱叫。游戏采用了标准OO技术,设计了一个鸭子超类Duck,并让各种鸭子继承此超类。
现在需要为鸭子添加新的行为Fly。如果在SuperClass中添加Fly则会使所有的鸭子对象都具有该方法。但实际中有些鸭子(例如橡皮鸭)是不会飞的。这种情况下只能在橡皮鸭子类中覆盖Fly。这无疑比较丑陋。
利用继承来提供Duck的行为,这会导致下列哪些缺点?
- 代码在多个子类中重复
- 运行时行为不容易改变
- 很难知道所有鸭子的行为
- 改变会牵一发而动全身,造成其他鸭子不想要的改变
如果采用接口呢
每个会飞的子类都需要实现Fly接口,会出现大量重复代码,没有做到代码复用。
软件开发的一个不变真理:CHANGE
由于种种原因,我们所写的代码会一直根据需求变动。实际上代码维护的时间远远超过了代码开发的时间。所以在写代码时一定要让代码灵活有弹性。
设计原则:
1. 封装变化:找出应用中可能需要变化之处,把它们独立出来,不要和那些不需要变化的代码混在一起
2. 针对接口编程,而不是针对实现编程
3. 多用组合,少用继承
根据第一条原则,我们应该将鸭子的行为从Duck中分离出来,建立一组新类来表示每个行为。
根据第二条原则,每个行为类都应该实现对应的接口
实现代码:
//超类
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 setFlyBehavior(FlyBehavior fb){
flyBehavior = fb;
}
//动态设定鸣叫行为
public void setQuackBehavior(QuackBehavior qb){
quackBehavior = qb;
}
public void swim(){
System.out.println("All ducks float, even decoys");
}
}
//飞行接口
public interface FlyBehavior {
public void fly();
}
//鸣叫接口
public interface QuackBehavior {
public void quack();
}
//翅膀飞行类
public class FlyWithWings implements FlyBehavior {
public void fly(){
System.out.println("i am flying");
}
}
//不会飞类
public class FlyNoWay implements FlyBehavior {
public void fly(){
System.out.println("I can not fly");
}
}
//鸭叫类
public class Quack implements QuackBehavior {
public void quack(){
System.out.println("I am quacking");
}
}
//不能叫类
public class MuteQuack implements QuackBehavior{
public void quack(){
System.out.println("I can not quack");
}
}
//吱吱叫类
public class Squeak implements QuackBehavior{
public void quack(){
System.out.println("squeak");
}
}
//野鸭类
public class MallardDuck extends Duck {
public MallardDuck(){
quackBehavior = new Quack();
flyBehavior = new FlyWithWings();
}
public void display(){
System.out.println("i am a real mallardduck");
}
}
//测试类
public class MiniDuckSimulator {
public static void main(String[] args){
Duck mallard = new MallardDuck();
if (mallard == null){
System.out.println("mallard is null");
}
mallard.performFly();
mallard.performQuack();
}
}
整体格局
上面代码实现的就是我们的第一个模式——策略模式
策略模式:
定义了算法族,分别封装起来,让他们之间可以互相替换,此模式让算法的变化独立于实用算法的客户。