搭配行为--策略模式

策略模式的核心思想,我们称之为:搭配行为。

就是说对于一个类,我们可以动态的去给他搭配一个行为,重点是,我们还可以在需要的时候,去替换他的行为。

按照我们以往的思维,行为就是方法。方法要如何搭配和替换呢?


我们以经典的对战游戏--魔兽争霸为例,来开始我们的策略模式探索之旅。

魔兽争霸中有一个英雄,叫剑圣。剑圣和其他英雄一样,有一个行为,叫移动。那么,如果要我们去设计英雄及其行为的话,应该首先会有一个英雄超类Hero,应该是抽象类或接口,以让不同的英雄自己去实现行为。我们只以移动这个行为为例,让剑圣去继承Hero,实现移动的行为,下面是Hero和BladeMaster的代码:

public abstract class Hero
{
      public abstract void move();
}

public class Blademaster implements Hero
{
      @Override
       public void move()
       {
             System.out.println("blademaster moving...");
       }
}

我们以一句简单的输出来模拟剑圣的移动行为。

如果是其他英雄,我们也让其继承Hero,多态的实现,目前来看,谁能说这样的设计不好呢?


现在问题来了,我们知道,剑圣有一个技能,叫疾风步,当使用了疾风步技能之后,剑圣将进入隐身状态,并且移动速度大大加快,也就是说,他的移动这个行为发生了改变。那我们如何应付移动行为改变这个事情呢?方法是写死的,我们不可能在程序运行过程中修改方法吧。请别忘了,玩家可能在程序运行的任何时候去使用剑圣的疾风步。

你可能想到创建一个记录状态的变量fasterMoving,当使用了疾风步时,改变这个变量的状态,然后在move方法里面,根据这个变量的不同状态,去做不同的行为:

public class Blademaster extends Hero
{
      private boolean fasterMoving = false;
      public void setFasterMoving(boolean isFaster)
      {
            this.fasterMoving = isFaster;
      }
      @Override
       public void move()
       {
             if(!fasterMoving)
             {
                  System.out.println("blademaster moving...");
             }else
             {
                   System.out.println("Blademaster faster moving...");
             }
       }
       
}
又是if..else, 如果以后移动行为又有了第三种状态,又要继续在这里添加一个else吗?

请记住,修改是设计的大忌。记住开闭原则--对扩展开放,对修改关闭。就是说尽量不要去修改原有的代码。


在设计模式中,有一个重要的原则,就是将变化的部分分离出来,不要和不变的部分混在一起。在这里,move方法成了一个变化的因素,所以,我们将move方法分离出来,好让其他部分更稳定。

那么分离出来的行为该怎么设计呢?

既然分离,那就分的彻底,将移动这个行为交给别的对象去做,我们称为委托。委托别的对象实现移动这个行为。或者更形象一点,把移动这种麻烦的事情,外包给别人去做。

而英雄类自己,只需要认识一个提供移动这种行为的对象就行了。

就是这样了,在英雄类中增加一个成员变量,而这个成员变量就是帮忙完成移动行为的,具体请看代码:

public class Hero
{
      private MoveBehavior moveBehavior;
      public void move()
      {
            moveBehavior.move();
      }
      public void setMoveBehavior(MoveBehavior behavior)
      {
           this.moveBehavior = behavior;
      }
}

public class Blademaster implements Hero
{
       public Blademaster()
       {
             this.moveBehavior = new BMGeneralMoveBehavior();
       }
}

增加了一个成员moveBehavior,并提供set方法。当move方法被调用时,实际上程序会去调用moveBehavior的move方法。以下是MoveBehavior接口以及两个实现类的代码:

public interface MoveBehavior {

	public void move();
}

public class BMGeneralMoveBehavior implements MoveBehavior {
 //此类表示剑圣正常的移动行为
	@Override
	public void move() {
		System.out.println("Blademaster moving...");
	}
}

public class BMFasterMoveBehavior implements MoveBehavior {
 //此类表示剑圣使用疾风步时的移动行为
	@Override
	public void move() {
		System.out.println("Blademaster faster moving...");
	}
}

这样做的意义是,当剑圣使用疾风步时,程序会调用剑圣对象的setMoveBehavior方法,将moveBehavior成员换成一个BMFasterMoveBehavior的对象,当再次调用move方法是,剑圣表现出来的就是BMFasterMoveBehavior的移动行为了。现在,在英雄类中,move方法不用变化了,需要变化的现在是成员moveBehavior。

以下是一段模拟游戏中剑圣移动行为的代码,我们添加了一个监听的功能,监听游戏中玩家使用了某些功能键,就可以触发移动行为或开启疾风步技能,我们定义一个actionPerformed方法,当监听到功能键时,会调用这个方法,并判断按下的是移动功能键还是疾风步功能键,如果是移动功能键,将调用move方法(本质上是调用moveBehavior的move方法),如果是疾风步功能键,将调用setMoveBehavior方法,重新设置moveBehavior:

public void actionPerformed(String key){
        if("move".equalsIgnoreCase(key)){
                blademaster.move();
        }else if("faster".equalsIgnoreCase(key)){
                blademaster.setMoveBehavior(new BMFasterMoveBehavior());
        }
}
这样,在按完疾风步键之后的移动行为,都表现为BMFasterMoveBehavior中所定义的快速移动的方式。还有,当疾风步结束后,也会调换setMoveBehavior方法,把moveBehavior设置成BMGeneralMoveBehavior对象:

                          blademaster.setMoveBehavior(new BMGeneralMoveBehavior());

随机应变,根据不同的情况,设置不同的行为方式,这就是策略。

定义策略模式:

              策略模式定义了算法族,分别封装起来,让他们之间可以互相替换。此模式让算法的变化独立于使用算法的客户。

所谓互相替换,就是我们例子中调用set重新设置行为的过程。


值得一提的另外一个概念,是面向对象中的组合,组合我们经常遇到,但可能并没有认真考虑过他的好处。

我们的例子中,Hero对象中,有一个成员,是MoveBehavior对象,面向对象中这种两个对象一个被另一个所引用或互相引用的情况,就叫组合。组合的意义在于对象之间互相协作,帮助。策略模式便是将组合的魅力发挥的淋漓尽致的一种设计模式。


看完本文,如果你能回过头,重新理解本文开头“搭配行为”四个字的含义,那你便已经掌握了策略模式的真谛!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值