策略模式用一句话来说,就是将一系列不同的方法(算法)都封装到不同的类当中,并使它们之间可以互相互换。并且这些方法可以独立于使用它们的客户而变化。
这句话看上去也许看不懂,但是我相信,等你看完这篇文章再回头看这句话,你就会有理会了。
我们来假设一下,假如现在你是拳头公司的一个设计师,让你来制作英雄联盟里面的英雄,你该怎么做?
大多数人肯定会想到,一定要有一个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方法的问题。
那么,我们如何解决这个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;
}
}
如果上面的方法明白了,那么策略模式您也就明白了。就是当我们需要动态改变方法的时候,我们可以将这个方法放置在一个成员对象里面,而不是类自己里面的方法,这样,我们可以通过修改这个成员变量的值,从而改变我们使用的这个类的方法。
现在,你在回头看看文章的第一段,有木有体会呢??有的话点个赞吧!!