一款游戏中的某个BOSS,根据当前血量不同,有几种不同状态。满血1000时是平静状态,不会攻击玩家;小于1000大于500是攻击状态,会用普通的技能攻击离他最近的玩家;小于500大于0是狂暴状态,会发动终极技能周期性的对周围所有玩家造成大量伤害;等于0是死亡状态,会在尸体上提供随机装备给予玩家。在BOSS的技能中,有一系列的恢复技能--可以为自己加血。除了死亡时,随时可能释放。所以,除了死亡状态不能逆转,其他几个状态都可能因为血量的变多变少而来回切换。如果直接实现一个复杂的BOSS类的话,需要在类中记录血量、状态,并随时if else判断boss的血量来设定状态,并if else的判断状态来释放不同的技能。这样的代码充斥了大量的if else,非常难看、维护性差。同时扩展性也差,如果增加一个状态,需要对原有代码进行不小的修改。这种情况可以使用状态模式来解决,每种状态下的行为和属性封装在一个状态类中,以此分散不同的条件,具有更好的灵活性、扩展性。
当系统中某个对象存在多个状态,这些状态之间可以进行转换,而且对象在不同状态下行为不相同时可以使用状态模式。
状态模式(State Pattern):允许一个对象在其内部状态改变时改变它的行为,对象看起来似乎修改了它的类。其别名为状态对象(Objects for States),状态模式是一种对象行为型模式。
简单结构如下:
文章开头的例子,可以实现为:
public abstract class State {
public abstract void handle();
}
public class PeaceState extends State {
@Override
public void handle() {
//DO SOMETHING
}
}
public class Boss {这样将各种状态的逻辑和行为从BOSS类中抽离出来,降低了复杂性,扩展也方便了。这里还存在一个状态切换的问题,有两种方式实现:
private Double HP;
private State state;
public void request(String action) {
//some thing
state.handle();
//some thing
}
}
- 在BOSS类中实现一个方法,根据血量控制状态的切换。
- 在State的逻辑中控制状态的切换。
总结:状态模式通过将一个类实例在不同状态下的不同行为状态封装成一个状态类,为对象设置不同的状态实现可变因素的内部转换。这些对客户端透明,方便使用。
优点:
- 封装了可变因素,状态的切换变得简单,提高了可维护性。
- 可以共享状态,减少代码量和实例数量。
- 增加了类的数量
- 结构较为复杂,增加了设计和理解难度
- 无论使用哪种状态转换方式,都一定程度上会违反开闭原则。
- 某类对象具有多个可转换的状态,并且对象的行为依赖状态。
- 状态的行为和条件繁琐,混在一起可维护性、可扩展性差。