一、例子
令狐冲被岳不群罚在思过崖上面壁思过。偶然的机会发现崖内有一个后洞,石壁上刻有魔教十长老尽破五岳剑派的图形招式。所有五岳剑派引以为豪的精微奥妙招式尽数被破得干干净净,包括一些已经失传的招式。
有一天采花大盗田伯光上思过崖来找令狐冲,让令狐冲随他下崖去见仪琳。仪琳思念令狐冲,她老爹不戒和尚点了田伯光死穴喂了毒药逼他把令狐冲带到仪琳面前以解仪琳相思之苦,若一月之内拿不到解药,就无药可救了。他必须要把令狐冲带下崖去,令狐冲死活不去。师父师娘为了田伯光在长安附件做了几起大案,影响到华山派声誉,已下山去诛杀田伯光。
当时令狐冲手上功夫和内力轻功等都远不如田伯光。田伯光用激将法引得令狐冲和他打了一个赌,如果令狐冲能接他三十招,他拍拍屁股走人,从此再也不让令狐冲随他下崖,如果接不了三十招,令狐冲就乖乖跟他走。
不管令狐冲用本门剑法还是从石壁上现学现卖的衡山、恒山、嵩山、泰山剑法都接不了田伯光三十招。后来华山派的归隐高手风清扬看得兴起,指点了令狐冲几句,先使一招‘白虹贯日’,跟着便使‘有凤来仪’,再使一招‘金雁横空’,接下来使‘截剑式’…将华山剑法打乱顺序来使,剑术之道,讲究如行云流水,任意所至,中间剑招不连贯的地方可以别出心裁,随手配合,一切须当顺其自然,行乎其不得不行,止乎其不得不止,中间不可有半点勉强。这一指点,令狐冲登时就接了田伯光一百多招,后来再经风清扬传授几招独孤九剑,田伯光就再也不是对手了。
接下来用代码实现令狐冲和田伯光比武的场景,令狐冲中间换了好几门剑法和田伯光比试。先来定义一个功夫的接口,令狐冲用到的剑法类以及田伯光用到的刀法类要实现此接口。
/**
* 功夫的接口,两个方法,包括这门功夫的
* 进攻方式和这门功夫的威力
*
*/
public interface IKungfu {
//攻击方式
void attack();
//威力(1~10代表威力等级)
int power();
}
功夫的接口IKungfu有两个方法,一个是功夫的招式,它的攻击方式attack,以及这门功夫的威力power,威力共分十个等级,数字越大,威力越大。
令狐冲用到了华山剑法,写一个华山剑法的类HuaShanSword实现功夫接口:
/**
* 华山派剑法
*
*/
public class HuaShanSword implements IKungfu{
@Override
public void attack() {
System.out.println("使出华山剑法");
}
@Override
public int power() {
return 5;
}
}
华山剑法的威力为5。令狐冲又用到了嵩山剑法,写一个嵩山剑法的类SongShanSword实现功夫接口:
/**
* 嵩山派剑法
*
*/
public class SongShanSword implements IKungfu {
@Override
public void attack() {
System.out.println("使出嵩山剑法");
}
@Override
public int power() {
return 6;
}
}
华山剑法的威力为6。后来,风清扬又传授了令狐冲在那时候天下无敌的独孤九剑,写一个独孤九剑的类NineSwordsOfDugu 实现功夫接口:
/**
* 独孤九剑
*
*/
public class NineSwordsOfDugu implements IKungfu {
@Override
public void attack() {
System.out.println("使出独孤九剑");
}
@Override
public int power() {
return 10;
}
}
独孤九剑的威力最大,等级最高,为10。田伯光用到的刀法类TianBoGuangSword同样实现:
/**
* 泰山派剑法
* @author Administrator
*
*/
public class TianBoGuangSword implements IKungfu{
@Override
public void attack() {
System.out.println("使出田伯光刀法");
}
@Override
public int power() {
return 7;
}
}
田伯光的快刀威力(7)比令狐冲使出来的华山剑法(5)和嵩山剑法(6)威力还大。
相关的功夫接口和类实现完了,接下来需要定义使用这些剑法刀法的侠客的类了:
/**
* 侠客
*
*/
public class Swordsman {
private String name;//侠客的名字
private IKungfu kungfu;//侠客用到的功夫
private Swordsman opponent;//侠客的对手
public Swordsman(String name, IKungfu kungfu) {
this.name = name;
this.kungfu = kungfu;
}
//侠客和对手比武
public void fightWith(Swordsman swordsman) {
this.opponent = swordsman;
System.out.print(name+":");
this.kungfu.attack();
System.out.print(swordsman.name+":");
swordsman.kungfu.attack();
fightResult();
}
//侠客与对手比武的结果
private void fightResult() {
if (this.kungfu.power() > opponent.kungfu.power()) {
System.out.println("比武结果:"+name+"赢了!"+opponent.name+"输了!");
} else if(this.kungfu.power() < opponent.kungfu.power()) {
System.out.println("比武结果:"+name+"输了!"+opponent.name+"赢了!");
} else{
System.out.println("比武结果:"+name+"和"+opponent.name+"打平了!");
}
}
//比武时可以更换用到的功夫
public void replaceKungfu(IKungfu kungfu) {
this.kungfu = kungfu;
}
}
这个类有两个public方法,一个是和对手比武的方法fightWith,以及比武时更换用到的功夫的方法replaceKungfu。
功夫和侠客都已经有了,下面就让令狐冲和田伯光在思过崖(SiGuoYa)上开始比试了:
public class SiGuoYa {
public static void main(String[] args) {
//令狐冲出场
Swordsman lingHuChong = new Swordsman("令狐冲", new HuaShanSword());
//田伯光出场
Swordsman tianBoGuang = new Swordsman("田伯光", new TianBoGuangSword());
//第一回合,令狐冲用本门剑法(华山剑法)和田伯光的刀法比试
System.out.println("-----第一回合-----");
lingHuChong.fightWith(tianBoGuang);
System.out.println("\n-----第二回合-----");
//第二回合,令狐冲换嵩山剑法和田伯光比试
lingHuChong.replaceKungfu(new SongShanSword());
lingHuChong.fightWith(tianBoGuang);
System.out.println("\n-----第三回合-----");
//第三回合,令狐冲换独孤九剑与田伯光比试
lingHuChong.replaceKungfu(new NineSwordsOfDugu());
lingHuChong.fightWith(tianBoGuang);
}
}
下面是他们的比武结果:
-----第一回合-----
令狐冲:使出华山剑法
田伯光:使出田伯光刀法
比武结果:令狐冲输了!田伯光赢了!
-----第二回合-----
令狐冲:使出嵩山剑法
田伯光:使出田伯光刀法
比武结果:令狐冲输了!田伯光赢了!
-----第三回合-----
令狐冲:使出独孤九剑
田伯光:使出田伯光刀法
比武结果:令狐冲赢了!田伯光输了!
再来整体上看看上面场景的类图:
二、策略模式
上面就是一个策略模式的例子。
策略模式定义了算法族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化独立于使用算法的客户。
策略模式特意将算法与其他部分分离开来,只是定义了与算法相关的接口,然后再在程序中以委托的方式来使用算法。使用委托这种弱关联关系可以很方便地整体替换算法。在上面的例子中功夫IKungfu就是一个算法的接口,华山剑法HuaShanSword、嵩山剑法SongShanSword、独孤九剑NineSwordsOfDugu等是功夫IKungfu接口的具体实现,在令狐冲和田伯光的比试中,令狐冲可以很方便地切换武功,华山、嵩山、衡山、恒山、泰山五岳剑派的剑法以及风清扬传授的独孤九剑可以随意切换。