英雄联盟开发例子生动形象地为你讲解StrategyPattern------策略模式

策略模式用一句话来说,就是将一系列不同的方法(算法)都封装到不同的类当中,并使它们之间可以互相互换。并且这些方法可以独立于使用它们的客户而变化。

这句话看上去也许看不懂,但是我相信,等你看完这篇文章再回头看这句话,你就会有理会了。

我们来假设一下,假如现在你是拳头公司的一个设计师,让你来制作英雄联盟里面的英雄,你该怎么做?

大多数人肯定会想到,一定要有一个Hero类,Hero类里面有攻击方法(attack()),移动(move()),还有你的一些Q,W,E,R基础和D,F召唤师技能。于是,我们得到了这样的代码:

public class Hero
{
public void attack();//执行攻击的方法
public void move();//鼠标右键移动
public void Q();//按了Q施放技能     (由于w,e,r类似,我就只写一个了)
public void D();//按了D技能  (F类似)
}


我们接下来会想,有了这个Hero类之后,我每设计一个英雄,就让他继承这个Hero类,比如我们来设计一个审判天使凯尔(kayle)这个英雄:

public class Kayle : Hero
{
}


由于继承的特性,我们的审判天使kayle也可以攻击,也可以移动,有了q,w,e,r,d,f这些函数。但是,我们很快想到,这些方法全都和Hero一样,这并不是我们kayle这位天使的特有技能。

接下来,也很自然,我们会想到在kayle子类中改写q,w,e,r这些方法,让这四个技能是kayle特有的技能。于是得到下面的类代码:

public class Kayle : Hero
{
public void Q()
{ ......   //kayle特有的Q技能};
}


但是,我们又会发现,d,f这两个技能并不是kayle类特有的技能,它会随着玩家选择的变化而改变(对于没有玩过英雄联盟的读者,只需要知道“闪现”、”治疗”、“传送”等技能都是一个方法就可以了),还有就是attack()函数,它会随着kayle的E技能而变化,E会使得攻击再两种方式下切换,单体近战和群体远程(简单地说,就是E这个函数会改变attack函数里面的类容)。那么问题来了1.学挖掘机哪家强?2.如何在游戏运行的过程中改变这个attack()方法中的内容呢?3.我们如何把这个会随着玩家选择改变的d,f技能给他封装到kayle这个英雄中呢?

(我们来绕绕弯路,有时候绕绕弯路可以让你看到更多的风景!)

首先关于第一个问题,我相信大家心里都有答案了。

第二个问题:如何改变attack方法?也许你会想到再定义一个attack1(),但是,这样子非常不好,因为在引擎或者其他更高层的对象调用这个Hero类的时候,也许它只认定这个attack方法。再定义一个attack1方法不可取。

那么怎么办呢?

或许你还会想到用一个接口,定义了近战和远程攻击这两种攻击方法,甚至可以定义一些召唤师技能,当我们在实例化一个英雄的时候,根据选择的召唤师技能来改变d,f和攻击方式,然后通过我们创建的类来使用这些接口?? 我们来试试看:

public interface  SummonerSkill
{
public abstract void useSkill();
.....//召唤师技能的接口
}
public class Cure implements SummonerSkill
{
useSkill();
.....//治疗方法
}
public class  Flash implements SummonerSkill
{
useSkill();
.....//闪现方法
}
public interface  Attack
{
attack();//攻击接口
}

public class CloseFight implements Attack
{
attack();//近战方法
}
public class  FarFightimplements Attack
{
attack();//远战方法
}


此时我们需要两个变量,分别来表示d,f这两个方法。

我们此时的Hero类改成这样子:

public class Hero
{
SummonerSkill d,f;
Attack att;
public void attack();//执行攻击的方法
{
att.attack();
}
public void move();//鼠标右键移动
public void Q();//按了Q施放技能
{
......   //kayle特有的Q技能
}
}


我们来定义这个kayle,假设此时一个小学生选择了kayle,并且带了治疗。

public class Kayle : Hero
{
SummonerSkill d = new Cure();//此时,我们的D键就是玩家自己设置的治疗技能了! f 就不写了 (注意这里用了一个上转!)
Attack att = new CloseFight();//同上,一个上转。
public void attack();//执行攻击的方法
{
att.attack();//此时的攻击初始为近战!
}
public void move();//鼠标右键移动
public void Q();//按了Q施放技能
{
......   //kayle特有的Q技能
}
}


这样子看上去好像解决了我们的问题,但是要注意!! 我们的攻击方式是随着游戏进行的时候动态改变的!!! 召唤师技能并不要时刻不停的变换,但是我们的attack 是在整个游戏过程中,会频繁的changing!

因此,我们仅仅用接口这个方法也不能解决attack方法的问题。

那么,我们如何解决这个attack方式一直在变换的问题呢?

我们很快就会想到,如果类中有一个方法,可以重新改写我们的attack方法不就行了吗?我们来看看具体怎么做的:

我们假设这个方法在E中:

此时的类代码如下:

public class Kayle : Hero
{
SummonerSkill d = new Cure();
Attack att = new CloseFight();
public void attack();//执行攻击的方法
{
att.attack();//此时的攻击初始为近战!
}
public void move();//鼠标右键移动
public void E();//按了E施放技能,注意这里同时改变了attack的一些特征
{
......   //kayle特有的E技能
changeAttack( newFarFight());//注意,这里调用了改变攻击方式的方法!!!由近战变为远程攻击了
}
void changeAttack(Attack aaa)
{
att = aaa;
}
}


如果上面的方法明白了,那么策略模式您也就明白了。就是当我们需要动态改变方法的时候,我们可以将这个方法放置在一个成员对象里面,而不是类自己里面的方法,这样,我们可以通过修改这个成员变量的值,从而改变我们使用的这个类的方法。


现在,你在回头看看文章的第一段,有木有体会呢??有的话点个赞吧!!

你可能感兴趣的:(设计模式(Design,Pattern))