设计模式之策略模式


        先看设计模式的定义:

        策略模式(Strategy Pattern):定义了算法族,分别封装起来,让它们之间可相互替换,次模式让算法的变化独立于使用算法的客户。

         举个例子,大家应该都玩过武侠角色游戏,下面就以角色游戏为背景来介绍。假设公司需要做一款武侠游戏的角色模块,需求是这样:每个角色对应一个名字,每类角色对应一种样子,每个角色拥有一个逃跑、攻击、防御的技能。

          初步的代码:

          

/** 
* 游戏的角色超类
*
*/
public abstract class Role
{
protected String name;

protected abstract void display();

protected abstract void run();

protected abstract void attack();

protected abstract void defend();

}

 

  
public class RoleA extends Role {
public RoleA(String name) {
this.name = name;
}

@Override
protected void display() {
System.out.println("样子1");
}

@Override
protected void run() {
System.out.println("金蝉脱壳");
}

@Override
protected void attack() {
System.out.println("降龙十八掌");
}

@Override
protected void defend() {
System.out.println("铁头功");
}

}

         没几分钟,你写好了上面的代码,觉得已经充分发挥了OO的思想,正在窃喜,这时候项目经理说,在添加两个角色:

 

         RoleB(样子2,降龙十八掌,铁布衫,金蝉脱壳);

         RoleC(样子1,九阳神功,铁布衫,烟雾弹)。

         于是你觉得没问题,开始写代码,继续继承Role,写成下面的代码:

        

public class RoleB extends Role  {  

public RoleB(String name) {
this.name = name;
}

@Override
protected void display() {
System.out.println("样子2");
}

@Override
protected void run() {
System.out.println("金蝉脱壳");//从RoleA中拷贝
}

@Override
protected void attack()
{
System.out.println("降龙十八掌");//从RoleA中拷贝
}

@Override
protected void defend() {
System.out.println("铁布衫");
}

}

 

public class RoleC extends Role  {  
public RoleC(String name) {
this.name = name;
}

@Override
protected void display() {
System.out.println("样子1");//从RoleA中拷贝
}

@Override
protected void run() {
System.out.println("烟雾弹");
}

@Override
protected void attack() {
System.out.println("九阳神功");
}

@Override
protected void defend() {
System.out.println("铁布衫");//从B中拷贝
}

}

        写完之后,你自己似乎没有当初那么自信了,你发现代码中已经存在相当多重复的代码,需要考虑重新设计架构了。于是你想,要不把每个技能都写成接口,有什么技能的角色实现什么接口。简单一想,觉得这想法确实不错。但是实现起来会发现,接口并不能实现代码的复用,每个实现接口的类,还是必须自己写实现。于是,we need change!遵循设计的原则,找出应用中可能需要变化的部分,把它们独立出来,不要和那些不需要的变化的代码混在一起。我们发现,对于每个角色的display、attack、defend和run都有可能变化,于是我们必须把这些独立出来。再根据另一个设计原则:针对接口编程,而不是针对实现编程,于是我们把代码改造成这样:

 

        

public interface IAttack{
void attack();
}

         

public interface IDefend{
void defend();
}

         

public interface IDisplay{
void display();
}

         

public class AttackJY implements IAttack{

@Override
public void attack(){
System.out.println("九阳神功");
}

}

         

public class RunJCTQ implements IRun{  

@Override
public void run(){
System.out.println("金蝉脱壳");
}

}

 

public class DefendTBS implements IDefend {  

@Override
public void defend() {
System.out.println("铁布衫");
}

}

         这时候需要对Role的代码作出改变:

        

/** 
* 游戏的角色超类
*
*/
public abstract class Role {

protected String name;

protected IDefend defend;
protected IDisplay display;
protected IRun run;
protected IAttack attack;

public Role setDefend(IDefend defend) {
this.defend = defend;
return this;
}

public Role setDisplay(IDisplay display){
this.display = display;
return this;
}

public Role setRun(IRun run){
this.run = run;
return this;
}

public Role setAttack(IAttack attack){
this.attack = attack;
return this;
}

protected void display(){
displayBehavior.display();
}

protected void run(){
runBehavior.run();
}

protected void attack(){
attackBehavior.attack();
}

protected void defend(){
defendBehavior.defend();
}

}

         现在每个角色只需要一个name了:

         

public class RoleA extends Role{  
public RoleA(String name){
this.name = name;
}
}

         现在我们需要一个金蝉脱壳,降龙十八掌,铁布衫,样子1的角色A只需要这样:

        

public class Test{

public static void main(String[] args){
Role roleA = new RoleA("A");

roleA.setAttackBehavior(new AttackXL())//
.setDefendBehavior(new DefendTBS())//
.setDisplayBehavior(new DisplayA())//
.setRunBehavior(new RunJCTQ());

System.out.println(roleA.name + ":");

roleA.run();
roleA.attack();
roleA.defend();
roleA.display();

}
}

         经过这样的修改,现在所有的技能的实现做到了100%的复用,并且随便项目经理需要什么样的角色,对于我们来说只需要动态的设置一下技能和展示方式,这就是策略模式。

          现在我们回到定义,定义上的算法族:其实就是上述例子的技能;定义上的客户:其实就是RoleA、RoleB ......;我们已经定义了一个算法族(各种技能),且根据需求可以进行相互替换,算法(各种技能)的实现独立于客户(角色)。现在是不是很好理解策略模式的定义了。

          附上一张UML图,方便理解:

        

         最后总结一下OO的原则:

         1.封装变化(把可能变化的代码封装起来)

         2.多用组合,少用继承(我们使用组合的方式,为客户设置了算法)

         3.针对接口编程,不针对实现(对于Role类的设计完全的针对角色,和技能的实现没关系)

 


本站声明
本文转载自:http://xhmj12.iteye.com/blog/2239776     作者:xhmj12     发布日期:2015-08-31     本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。


 
© 2014-2016 ITdaan.com 粤ICP备14056181号