什么是策略模式: 定义了算法族,将他们封装起来,让他们之间可以相互替换,通常由一个接口或抽象类实现。此角色给出所有的具体策略类所需的接口。
现在我们假设一个场景:父类用户类(User),他有三个子类:游客(Tourist),普通用户(GeneralUser),vip用户(VIPUser)。他们都有一个购买行为。游客不可购买需要注册为普通用户,普通用户原价购买,vip九折购买。我们可以抽象User并加一个抽象方法Buy()。子类各自重写方法Buy()去对应每个购买方式。OK!你很快的实现了这个场景。可以隔几天老板又说了,我们得加一个超级会员,或者我们学腾讯一样,我们加些绿钻会员,粉钻会员,蓝钻会员,黑心会员(啊,呸!是黑钻会员)。你怎么办,难道给每个子类重写方法Buy()吗?其实问题是可以解决,但显得代码重用性极差,不够优雅,思想混乱,重复性代码可能会很多。在设计模式中有一个原则,大概意思就是:不要将可能变化得代码与不会变化得代码混在一起。这样做一旦需求有变哪怕是极小的也是一场灾难。在User中把可能变化的购买行为分出来,用接口BuyBehavior代替。同时在抽象父类中实现Buy()方法。甚至在假设购买方式本身不会变,变得只是用户定义的购买方式,我们可以动态的修改用户的购买方式(当然只是某个对象,想要修改子类的购买方式,只要在子类中写改不同的接口对应的实现类就好了),废话不多说,我们直接看代码:
interface BuyBehavior{
public void Buy();
}
//具体有哪些购买方法
class DisAllowBuy implements BuyBehavior{
@Override
public void Buy() {
System.out.println("游客无法购买");
}
}
class CostPriceBuy implements BuyBehavior{
@Override
public void Buy() {
System.out.println("普通用户原价购买");
}
}
class DiscountBuy implements BuyBehavior{
@Override
public void Buy() {
System.out.println("vip九折购买");
}
}
//定义子类的购买方式
class Tourist extends User{ //将游客的购买方式定义为无法购买
//注意这里继承了父类保护类型的接口BuyBehavior变量
public Tourist(){
bb = new DisAllowBuy();
}
}
class GeneralUser extends User{ //将普通用户的购买方式定义为原价购买
//注意这里继承了父类保护类型的接口BuyBehavior变量
public GeneralUser(){
bb = new CostPriceBuy();
}
}
class VipUser extends User{ //将vip用户的购买方式定义为九折购买
//注意这里继承了父类保护类型的接口BuyBehavior变量
public VipUser(){
bb = new DiscountBuy();
}
}
abstract class User{ //可以动态的修改子类的购买方式
protected BuyBehavior bb;
public void setBuyBehavior(BuyBehavior b){
bb = b;
}
public void Buy(){ //父类实现购买方式而不是将它抽象
bb.Buy();
}
}
public class Strategy {
public static void main(String[] args) {
User u1 = new Tourist();
User u2 = new GeneralUser();
User u3 = new VipUser();
User uu[] = {u1,u2,u3};
for(User e:uu){
e.Buy();
}
u1.setBuyBehavior(new CostPriceBuy());
u1.Buy();
}
}
输出结果:
游客无法购买
普通用户原价购买
vip九折购买
普通用户原价购买
我们可以看出代码中将购买方式单独放在接口BuyBehavior中,可以尽可能的将购买方式所有的不同实现方式写全。购买方式完全独立于用户,想要增加用户的类型无非就是增加购买方式,加一个超级会员,那么就编写一个超级会员的购买方式,在超级会员的子类构造函数将变量bb赋予这个实现类。我们从结果可以看到当游客对象u1调用方法setBuyBehavior()就改变了u1的购买方式了。
策略模式UML
在项目中怎么用策略模式呢
不知道大家有没有玩过最近很火的FPS类游戏《绝地求生》。游戏有别于其他Fps游戏的地方在玩家控制的人物刚开始是没有装备的,可以理解为User类的装备变量为null,噢,或者是拳头。然后人物不断去游走找散落在各地的枪,我可以理解就是有一个线程一直在监控玩家行为,当玩家确定捡某把枪的时候,就会去调用类似于上列代码中setBuyBehavior(BuyBehavior bb)。只不过参数为武器类的接口,接口不同的实现类又不同的武器性能。当你捡到一把狙的时候,开枪或者命中的伤害步枪强高就是因为你的狙实现类与步枪的实现类不同。当你不想要狙,换成步枪的时候又调用类似与setBuyBehavior(BuyBehavior bb)的方法;策略模式对于类与类之间解耦非常好用,当你有类似于一直变化的用户类型,而购买方式去很少变化时就可以使用策略模式将他们分开。