前言
我们在日常开发中经常会面临if-else的选择,比如我刚刚登录csdn,想写一篇关于状态模式的博客,发现cookie又没有保存我的登录信息(可能是过期了),当我点击博客时,会先提示需要登录,这里我们可以看到,我们用户的行为是由当前是否登录这个状态来决定的,这就是典型的状态模式情景。在逻辑判断较多,分支较为复杂的场景,状态模式的合理使用能让我们少写很多if-else。
UML
如图,状态模式包含以下三个角色:
- Context: 环境类,定义客户感兴趣的接口,维护一个State子类的实例,这个实例对应的是对象当前的状态。
- State:抽象状态类或者状态接口,定义一个或者一组行为接口,表示该状态下的行为动作。
- ConcreteStateA、ConcreteStateB: 具体状态类,实现State抽象类中定义的接口方法,从而达到不同状态下的不同行为。
示例
我们以在Csdn中读写博客为例来描述状态模式。
CsdnState
/**
* @author jhz
* @date 18-10-9 下午9:58
*/
public interface CsdnState {
public void login();
public void logout();
public void readBlog();
public void writeBlog();
}
首先定义状态接口,即State角色,定义用户的行为接口,包括登录下线以及读写博客,接着分别定义两种状态实现:登录状态和未登录状态。
LoginState
/**
* @author jhz
* @date 18-10-9 下午10:01
*/
public class LoginState implements CsdnState {
@Override
public void login() {
System.out.println("您已经登录!");
}
@Override
public void logout() {
System.out.println("下线成功!");
}
@Override
public void readBlog() {
System.out.println("浏览博客中...");
}
@Override
public void writeBlog() {
System.out.println("写博客中...");
}
}
LogoutState
/**
* @author jhz
* @date 18-10-9 下午10:03
*/
public class LogoutState implements CsdnState {
@Override
public void login() {
System.out.println("登录成功!");
}
@Override
public void logout() {
System.out.println("您未登录!请先登录!");
}
@Override
public void readBlog() {
System.out.println("浏览博客中...");
}
@Override
public void writeBlog() {
System.out.println("您未登录!请先登录!");
}
}
这两个具体的状态实现类即ConcreteState角色,并分别描述不同状态下的行为。
Person
/**
* @author jhz
* @date 18-10-9 下午10:09
*/
public class Person {
CsdnState state;
public void setState(CsdnState state) {
this.state = state;
}
public void Login(){
setState(new LoginState());
}
public void Logout(){
setState(new LogoutState());
}
public void readBlog(){
state.readBlog();;
}
public void writeBlog(){
state.writeBlog();
}
}
person类负责状态的变更控制,即Context角色。
客户类
/**
* @author jhz
* @date 18-10-9 下午10:13
*/
public class Client {
public static void main(String[] args) {
Person person = new Person();
//登录csdn并开始读写博客
person.Login();
person.readBlog();
person.writeBlog();
//下线并开始读写博客
person.Logout();
person.readBlog();
person.writeBlog();
}
}
接着写个客户类测试下结果:
小结
在对象的行动取决于本身的状态时,可以适用于状态模式,免去了过多的if–else判断,这对于一些复杂的和繁琐的判断逻辑有很好的帮助。但是使用状态模式,势必会造成更多的接口和类,对于非常简单的状态判断,可以不使用。