Head First-策略模式(Strategy Pattern)

来源:互联网 发布:星空地图软件 编辑:程序博客网 时间:2024/06/04 17:46

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

         策略模式是一个相对比较简单的模式,优势是把程序段中的不确定因素内聚处理。起初是用来在不同需求之间选用不同算法来进行处理。能够很好的迎合客户需求的变化,使代码有更好的维护性和扩展性。此模式最大限度采取组合(composition)替代继承的方法,使建立的系统具有很大的弹性,不仅可以将算法族封装成类,更甚可以在运行时实现动态的行为改变。而这种模式的缺点也很明显,对策略类的抽象势必会造成很多策略类。如果对这种类的处理稍有不慎就会使整个类关系紊乱。另外一个缺点是客户端必须知道所有的策略类,安全性尚且不谈,对客户端软件规模就是一种挑战。

         举个例子:

         一个动作冒险游戏项目,游戏中会出现各种人物(KingQueen),装备各种武器,有的是剑(sword),有的是(knife)、、、、、、、、、

1.       首先对这个需求进行分析

public class Character{int experience;public void fight();  //人物攻击    public void condition();  //人物的状态,这里只有武器。}


看到这个需求时,一般的程序员脑海里马上就有了想法。先建立一个人物基类,然后,抽象出人物的行为方法。


然后,让King,Queen。。。。等分别继承Character类就好了。大功告成

    但是,可怕的问题发生了。。。。。客户需求变化

骑士(Knigh)到了十级以后怎么能没坐骑呢。好,没有难度,在character类里面加入下面的方法:

public void rideHorse(); //人物的坐骑(黄骠马,大宛马,汗血马、、、o(╯□╰)o

问题又来了,你让王后(Queen)也骑个马也太不伦不类了吧、、、、、

         好,继续,用interface,只让会骑马的人物来实现rideHorse函数。那只能说是个超笨的idea,这样使重复代码变的超级多。如果Knight又升级了,要骑天龙,一个个去改去吧。

2.       再分析

并不是所有的子类都具有rideHorse行为,而且子类的Weapon人物不同也不尽相同。这时使用继承就不能很好的解决问题,因为行为总是在变化。接口也是不错,但是接口不具有实现的代码,无法达到代码复用的结果。

问题已经明确了,每次一有需求改变,或者有新的需求进来,都会使某方面的代码发生变化,需要做的就是把这段代码变化的部分抽象出来。

3.       再设计

首先,人物的武器会变化,所以把weapon抽象出来,完全脱离Character类。

//对武器状态抽象出来的接口
public interface weaponBehavior(){
    public void fight();
}

各种武器的实现。

//对各种武器的实现
 
//knife
public class knifeBehavior implements weaponBehavior{
    public void fight(){
        //
实现刀攻击的方法
        System.out.println("Fight with Knife.");
    }
}
//Axe
public class axeBehavior implements weaponBehavior{
    public void fight(){
        //
实现斧攻击的方法
        System.out.println("Fight with Axe.");
    }
}
//Sword
public class swordBehavior implements weaponBehavior{
    public void fight(){
        //
实现剑攻击的方法
        System.out.println("Fight with Sword.");
    }
}
//Bow
public class bowBehavior implements weaponBehavior{
    public void fight(){
        //
实现弓箭攻击的方法
        System.out.println("Fight with Bow.");
    }
}

         对人物基类的设计。

         public abstract class Character{
    weaponBehavior weapon;
    public Character(){}
 
    public abstract void fight(){
        //委托行为类
        weapon.fight();
    }

public  condition();
}

各种人物的实现。

//King的实现
public class King extends Character{
    public King(){
        weapon = new swordBehavior();
    }
    public conditon(){
        System.out.println("My weapon is Sword.");
    }
}
//Queen的实现
public class Queen extends Character{
    public Queen(){
        weapon =  new knifeBehavior();
    }
    public conditon(){
        System.out.println("My weapon is Knife.");
    }
}
//Knight的实现
public class Knight extends Character{
    public Knight(){
        weapon =  new bowBehavior();
    }
    public conditon(){
        System.out.println("My weapon is Bow.");
    }
}
//Troll的实现
public class Troll extends Character{
    public Troll(){
        weapon =  new axeBehavior();
    }
    public conditon(){
        System.out.println("My weapon is Axe.");
    }
}

最后编写测试类来进行测试。

public class Test(){
    public static void main(String args[]){
        Character King = new King();
        King.fight();
        King.conditon();
    }
}

这样基本上实现了需求。

策略模式也可以用来动态的设定行为。比如在这里给人物换装备。

在Character基类中加入一个新方法

//实现给人物换装备的功能,要传入一个装备。
public void setWeaponBehavior(weaponBehavior wb){
    weapon = wb;
}

再进行测试

public class Test(){
    public static void main(String args[]){
        Character King = new King();
        King.fight();
        King.conditon();
        King.setWeaponBehavior(axeBehavior);
        King.fight();
    }
}

这样整个项目就完成了,骑马功能还没处理好,有空再写吧,或者交给别人,困死了,如果不出什么意外的话就差不多可以交付了。

         到这里才觉得发现这个例子举的其实不是很好,到后面发现不光对攻击动作可以抽象,对武器其实也应该抽象。可以把武器设置成一个参数传入fighcondition方法中。这样会使代码的整体性更强。但是那属于装饰者模式的范畴了。

         回头想想,只做了两件事,对可能变化的部分进行封装,放在一起,把它从继承中挖割出来。第二件事是把继承转换成组合。这种模式对需求变化性问题的解决是很好的key

 

OO设计原则:一)多用组合,少用继承。

                               二)针对接口编程,而不是针对实现编程。

                               三)找出应用中可能需要变化的地方,把他们独立出来,不要和不需要变化的代码放在一起。(封装变化)

                              四)松耦合,高内聚

 

0 0
原创粉丝点击