《魂斗罗归来》之状态模式VS策略模式
掘金:https://juejin.im/post/59fc3b9151882574d172498e
欢迎收看俗到掉渣的《小Y讲堂》节目,大家好,我是小Y,一个集性感毛发与才华于一身的程序猿。小Y的设计模式系列中的「状态模式」和[「策略模式」](http://www.jians
hu.com/p/c59d75de1c54)都已经总结完成了,很多小伙伴都会凌乱在这两种模式当中,小Y曾经也被凌乱到无法自拔。。。
一、模式对战前的准备
两个类图都非常相似,都是通过Context类封装了一个具体的行为,都提供了一个封装方法,是高扩展性的设计模式。它们就像一对孪生兄弟一样,通过通用UML根本没有办法区分出不同之处。小Y举个例子来区分它们之间的不同点。
小Y玩《魂斗罗归来》有自己的一套方法和习惯,每次都会按照先闯关卡对战☞1vs1对战模式☞3vs3对战模式的顺序来进行游戏冲关(突然感觉小Y的强迫症在加重…)。1vs1、3vs3、关卡对战至关重要的一点就是要选择武器,1vs1模式选择的武器就是狙击枪+喷射器,3vs3模式选择的武器是炮类+突击步枪,关卡对战选择的武器是机关枪+突击步枪。按照策略模式来分析,根据三种对战模式选择武器就是三个不同的具体算法,算法之间没有交互,以达到算法可以*切换,随着不同的对战模式而进行武器的更换;按照状态模式来分析,小Y的打游戏的顺序(关卡对战☞1vs1对战模式☞3vs3对战模式)就被看做三个不同的状态,每个状态的改变,就会引起行为的变化,同时每个状态的变化都会指定下一个状态。
二、策略模式实现武器切换
1.策略模式武器切换类图
2.切换的代码清单
①武器切换抽象类
public abstract class ISwitch {
public abstract void switch();
}
②关卡对战模式
public class BarrierFight extends ISwitch {
public void switch() {
System.out.println("BillRizer选择的武器:机关枪+突击步枪");
}
}
③1vs1对战模式
public class OnetoOneFight extends ISwitch {
public void switch() {
System.out.println("BillRizer选择的武器:狙击枪+喷射器");
}
}
④3vs3对战模式
public class ThreetoThreeFight extends ISwitch {
public void switch() {
System.out.println("BillRizer选择的武器:炮类+突击步枪");
}
}
⑤对战模式
public class Context {
//构造函数,要使用玩哪种模式
private ISwitch switchStrategy;
public Context(ISwitch switchStrategy){
this.SwitchStrategy = switchStrategy;
}
//根据不同模式选择不同武器
public void switch(){
this.switchStrategy.switch();
}
}
⑥使用不同武器
public class xiaoY {
//小Y开始打游戏了,根据不同模式选择了不同的武器
public static void main(String[] args) {
Context context;
//关卡对战模式
context = new Context(new BarrierFight());
context.switch();
//1vs1对战
context = new Context(new OnetoOneFight());
context.switch();
//3vs3对战模式
context = new Context(new ThreetoThreeFight());
context.switch();
}
}
输出的结果为:
①BillRizer选择的武器:机关枪+突击步枪
②BillRizer选择的武器:狙击枪+喷射器
③BillRizer选择的武器:炮类+突击步枪
三、状态模式实现武器切换
1.状态模式武器切换类图
2.切换的代码清单
①武器切换抽象类
public abstract class ISwitch {
protected Context context;
public void setContext(Context context){
this.context=context;
}
public abstract void switch();
}
②关卡对战模式
public class BarrierFight extends ISwitch {
public void switch() {
System.out.println("BillRizer选择的武器:机关枪+突击步枪");
super.context.setState(ONE_FIGHT_STATE);
}
}
③1vs1对战模式
public class OnetoOneFight extends ISwitch {
public void switch() {
System.out.println("BillRizer选择的武器:狙击枪+喷射器");
super.context.setState(THREE_FIGHT_STATE);
}
}
④3vs3对战模式
public class ThreetoThreeFight extends ISwitch {
public void switch() {
System.out.println("BillRizer选择的武器:炮类+突击步枪");
}
}
⑤对战模式
public class Context {
//定义对战的几种模式
public static final ISwitch BARRIER_FIGHT_STATE=new BarrierFight();
public static final ISwitch ONE_FIGHT_STATE=new OnetoOneFight();
public static final ISwitch THREE_FIGHT_STATE=new ThreetoThreeFight();
private ISwitch switchState;
public void setState(ISwitch switchState){
this.switchState = switchState;
this.switchState.setContext(this);
}
//根据不同模式选择不同武器
public void switch(){
this.switchState.switch();
}
}
⑥使用不同武器
public class BillRizer {
//比尔.雷泽出场了,他根据不同模式选择了不同的武器
public static void main(String[] args) {
Context context;
context = new Context();
//关卡对战模式
context.setState(new BarrierFight());
context.switch();
//1vs1对战
context.switch();
//3vs3对战模式
context.switch();
}
}
输出的结果为:
①BillRizer选择的武器:机关枪+突击步枪
②BillRizer选择的武器:狙击枪+喷射器
③BillRizer选择的武器:炮类+突击步枪
两种模式运行的结果都是相同的,但是两者的分析角度是大相径庭的,实现通过采用策略模式实现了“切换武器”这个策略的三种不同算法,算法可以*切换,到底用哪个算法由调用者决定,因此策略模式的使用重点是算法的*切换,增加新的算法对整体功能没有非常大的改变,非常灵活;而状态模式是从小Y打游戏闯关的顺序来分析,每个关卡代表的状态对应了不同的行为,状态改变后行为也随之改变,每个状态的变化都会指定下一个状态。
三、小结
从以上示例中我们也可以看出,对于相同的业务需求,有很多种实现方法,问题的重点是业务关注的是什么,只有找准了业务的焦点,才能够选择更加合适的设计模式。
虽然我们从通用UML图上称他们为亲兄弟,但是从上面的两个代码清单可以看出这两者还是存在着非常大的差别,很容易区分出来。
策略模式算法可以*切换,到底用哪个算法由调用者决定;状态模式是初始化一个状态,之后的每个状态的变化都会指定下一个状态。
环境角色的职责不同。两者都有一个叫做Context环境角色的类,但是两者的区别很大,策略模式的环境角色只是一个委托作用,负责算法的替换;而状态模式的环境角色不仅仅是委托行为,它还具有登记状态变化的功能,与具体的状态类协作,共同完成状态切换行为随之切换的任务。
应用场景不同。,策略模式只是一个算法的封装,可以是一个有意义的对象,也可以是一个无意义的逻辑片段;状态模式则要求有一系列状态发生变化的场景,它要求的是有状态且有行为的场景。
解决问题的方法不同。策略模式只是确保算法可以*切换,但是什么时候用什么算法它决定不了;状态模式对外暴露的是行为,状态的变化一般是由环境角色和具体状态共同完成的。
掘金地址:https://juejin.im/post/59fc3b9151882574d172498e
简书地址:http://www.jianshu.com/p/ac5b81102e9c