此文介绍我理解的状态设计模式,这是行为模式的一种,在很多需求的场景,一个对象的行为依赖对象的状态,这种场景很多,而且这种状态是可能持续迭代的,这种需求我们一般会给对象一个状态标志然后if-else判断去实现业务逻辑,这样每次来个新的状态都要增加 if-else,这样非常不好维护,需要去修改原来的类,不满足开闭原则。我举个例子,一个人的状态有很多种,穷或则富,或则中产,或则小康。不同的状态做同样的事情的感觉肯定不一样,而且以后可能还会增加新的人的分类。怎么去扩展呢。
按照不用模式的写法,是这样的:
public class Person {
private String status;
private String name;
//setter getter
}
然后一个调用类,各种行为需要判断人的状态:
class StateAction {
private Person person;
public StateAction(Person person) {
this.person = person;
}
public void show() {
// 变化剧烈,不好维护
if (person.getStatus() == "穷") {
drive("自行车");
dress("旧衣服");
System.out.println("....");
System.out.println("很穷的各种");
} else if (person.getStatus() == "富") {
drive("豪车");
dress("皮大衣");
System.out.println("....");
System.out.println("各种炫富啊");
} else if (person.getStatus() == "中产") {
// 如果以后还有各种状态...累死了, Bad smell
// T A T
}
// else if
}
private void drive(String msg) {
System.out.println(this.person.getName() + "开" + msg);
}
private void live(String msg) {
System.out.println(this.person.getName() + "住" + msg);
}
private void dress(String msg) {
System.out.println(this.person.getName() + "穿" + msg);
}
}
// 调用方法
Person person = new Person("小马哥");
// 不用模式
person.setStatus("穷");
StateAction stateAction = new StateAction(person);
stateAction.show();
person.setStatus("富");
stateAction.show();
这个是很正常的思维方式,这样是不好的,添加if else不好维护而且StateAction这个类承担了过多的指责,具体的对象状态与类的行为绑定死了,一旦一个状态的行为改变了,只能去改原先的逻辑,如果能达到一个动态的对象与行为的组合是更灵活的一种方式,把状态与人的行为与分离出来。能够让不同状态的行为变化能够动态的组合。
分析这个场景下的稳定部分与不稳定的部分
稳定的行为:
人的行为,那就是都有drive, dress, live这几个方法
不稳定的部分:
不同状态下的行为不稳定,可能有很多种行为方式集合
以下用状态的模式重写这块:
/**
* 状态模式,隔离状态的接口
* 这里描述了具体人的不同的状态
*/
interface State {
void dress();
void drive();
void live();
}
/**
* 抽象实现,传入person作为状态的上下文
* Person可以是抽象类,那样是不是就和桥模式非常像,可以动态组装两个维度的变化对象
* 这里主要演示人在不通状态下的不同行为,所以person为具体实现
*/
abstract class AbstractPersonState implements State {
protected Person person;
/**
* 传入上下文
* @param person
*/
public AbstractPersonState(Person person) {
this.person = person;
}
protected String getPersonName() {
return this.person.getName();
}
protected void print(String msg){
System.out.println(msg);
}
/**
* 展示下生活状态
*/
public void show() {
// 钩子方法
this.drive();
this.dress();
this.live();
}
}
/**
* 穷人状态
*/
class PoolPersonState extends AbstractPersonState implements State {
public PoolPersonState(Person person) {
super(person);
}
@Override
public void dress() {
print(getPersonName() + "穿旧衣服");
}
@Override
public void drive() {
print(getPersonName() + "开自行车");
}
@Override
public void live() {
print(getPersonName() + "住农民房");
}
}
/**
* 富豪状态
*/
class RichPersonState extends AbstractPersonState implements State {
public RichPersonState(Person person) {
super(person);
}
@Override
public void dress() {
print(getPersonName() + "穿皮大衣");
}
@Override
public void drive() {
print(getPersonName() + "开豪车啊");
}
@Override
public void live() {
print(getPersonName() + "住豪宅啊");
}
}
// 调用方式
PoolPersonState poolPersonState = new PoolPersonState(person);
poolPersonState.show();
RichPersonState richPersonState = new RichPersonState(person);
richPersonState.show();
动态的组合状态和对应的人,使其表现出不同的行为,如果有新的状态行为,只要定义新的AbstractState子类即可,在使用的地方就可以组合以下,而不用修改其他的代码,这样提高了代码的维护性和扩展性,满足了开闭原则并且分离了人与状态。
很多模式都很类似,这里的模式网上有很多文章大谈状态模式与策略模式的区别,因为从另一个角度,状态模式的确与策略模式非常类似,把状态State看成策略接口,再把AbstractPersonState看成环境类,就和策略模式如出一辙,的确,甚至把Person定义成抽象类或接口,也能看到桥模式的影子。策略模式解决的是一系列算法中差异算法的封装,可以看成是从另一个角度看待这个模式,而桥模式是从变化维度的角度来管控变化的。