设计模式——策略模式

阅读 《Head First设计模式》的个人笔记

简单的模拟鸭子应用做起

公司做了一套相当成功的模拟鸭子游戏:SimUDuck
游戏中会出现各种鸭子,一边游泳戏水,一边呱呱叫。此游戏的内部设计使用了标准的OO技术,设计了一个鸭子超类(superclass),并让各种鸭子继承此超类。
在这里插入图片描述

现在我们得让鸭子能飞

会飞的鸭子来将竞争者抛在后头。这有什么困难?
我只需要在Duck类中加上fly()方法,然后所有的鸭子都会继承fly()。这是我大显身手,真是OO才华的时候了。

在这里插入图片描述

但是可怕的问题发生了

股东会议上,有很多“橡皮鸭子”在屏幕上飞来飞去

怎么回事?

并非所有鸭子都会飞,即并非所有Duck的子类都会飞。
在Duck超类中加上新的行为,会使得某些并不合适该行为的子类也具有该行为。
(确实有一点小疏失。但是,他们怎么不干脆把这当成一种“特色”,其实还挺有趣的呀…)
在这里插入图片描述
可以把fly()方法覆盖掉,变成什么都不做,橡皮鸭就不会飞了。
但是如果以后加入了诱饵鸭,又会怎么样?诱饵鸭不会飞,也不会叫。

利用接口如何?

继承可能不是答案,因为以后可能会定期更新产品。入果每次都有新的鸭子出现,就要检查并可能覆盖fly()和quark()…这简直是无穷无尽的噩梦。
所以,需要一个更清晰的方法,让“某些“(而不是全部)鸭子类型可飞或可叫。
在这里插入图片描述
在这里插入图片描述
这样一来,重复代码会变多,如果后面有几十上百种鸭子,那么对于每个Duck的子类都要修改。
有代码不能复用的问题。

第二个设计原则:针对接口编程,而不是针对实现编程。

实现鸭子的行为

在此,我们有两个接口,FlyBehavior和QuackBehavior,还有它们对应的类,负责实现具体的行为:
在这里插入图片描述

这样的设计,可以让飞行和呱呱叫的动作被其他的对象复用,因为这些行为已经与鸭子类无关了。
而我们可以新增一些行为,不会影响到既有的行为类,也不会影响“使用”到飞行行为的鸭子类

整合鸭子的行为

关键在于,鸭子现在会将飞行和呱呱叫的动作“委托”别人处理,而不是使用定义在Duck类(或子类)内的呱呱叫和飞行方法。

在这里插入图片描述
在这里插入图片描述

测试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 swim() {
    System.out.println("All ducks float, even decoys!");
  }
}

野鸭类

public class MallardDuck extends Duck {

  public MallardDuck() {
    quackBehavior = new Quack();
    flyBehavior = new FlyWithWings();
  }

  @Override
  public void display() {
    System.out.println("I'm a real Mallard duck");
  }
}

飞行行为

public interface FlyBehavior {
  public void fly();
}

public class FlyWithWings implements FlyBehavior {

  @Override
  public void fly() {
    System.out.println("I'm flying");
  }
}

呱呱叫行为

public interface QuackBehavior {
  public void quack();
}

public class Quack implements QuackBehavior {

  @Override
  public void quack() {
    System.out.println("Quack");
  }
}

测试类

public class MiniDuckSimulator {

  public static void main(String[] args) {
    Duck mallard = new MallardDuck();
    mallard.performQuack();
    mallard.perFormFly();
  }
}

动态设定行为

在鸭子里建立了一堆动态的功能没有用到,就太可惜了!假设我们想在鸭子子类中通过“设定方法”来设定鸭子的行为,而不是在鸭子的构造器内实例化。

在Duck类总加入两个新方法:
  public void setFlyBehavior(FlyBehavior fb) {
    flyBehavior = fb;
  }

  public void setQuackBehavior(QuackBehavior qb) {
    quackBehavior = qb;
  }
制造一个新的鸭子类型: 模型鸭(Model Duck.java)
public class ModelDuck extends Duck{

  public ModelDuck(){
    flyBehavior = new FlyNoWay();
    quackBehavior = new Quack();
  }

  @Override
  public void display() {
    System.out.println("I'm a model duck");
  }
}
建立一个新的FlyBehavior类型
public class FlyRocketPowered implements FlyBehavior{

  @Override
  public void fly() {
    System.out.println("I'm flying with a rocket!");
  }
}

改变测试类,加上模型鸭,并使模型鸭具有火箭动力
public class MiniDuckSimulator {

  public static void main(String[] args) {
    Duck mallard = new MallardDuck();
    mallard.performQuack();
    mallard.perFormFly();
	
	//测试模型鸭,如果成功了,意味着可以动态地改变它的飞行行为。
	//如果把行为的实现绑死在鸭子类中,可就无法做到这样了
    Duck model = new ModelDuck();
    model.perFormFly();
    model.setFlyBehavior(new FlyRocketPowered());
    model.perFormFly();
  }
}
在运行时想改变鸭子的行为,只需要调用鸭子的setter方法就可以。
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值