我们在开发的时候,时刻会遇到一个对象允许的状态改变的时候其行为也同样的进行改变,或者我们在书写一个的类的时候,经常会根据来判断当前的状态(enum类)的去实现不同的方法。这个时候可以考虑用状态模式。
似乎从上面的反应来看,我们在上面的问题的也可以用来策略模式,但是状态模式和策略模式本质不是一样的,状态模式的行为都是平行,不可以相互替换的,但是策略模式的行为是相互独立的,可以相互也换的,换言之,状态的模式的行为的都是在一中状态的行为,所有的行为都存在一个联系。而策略模式,每个行为的都是彼此独立的。举个例子,电视机只有打开的状态的时候才能够调台,调节音量,等一系列操作,但是在关机的时候,是没法去调台和调节音量等操作的。这里的操作指的的是有效操作。
状态模式的介绍
状态模式的uml图
- Client :需要借助状态模式来实现客户端类
- States : 状态的抽象类
- StatesA: A状态下的实现类
- StatesB: B状态下的实现类
状态的模式例子。
在android中用户登录是一个常见的问题,如果存在用户系统,那么很多操作是需要区分的,比如分享,评论,就是跳转的操作。如果这个时候需要,如果标量标记是否登录,如果登录就继续下去,如果没有登录,则进入登录界面的,然后选择登录,登录成功会正常进入,登录失败则返回。如果逻辑过多的,则会造成if的嵌套,不利于维护和扩展。而在这里,我们可以使用的状态模式。
例子的uml图
例子的package图
例子的代码
UserStates
public interface UserStates {
void share();
void comment();
void video();
}
LoginUserStates
public class LoginUserStates implements UserStates {
@Override
public void share() {
System.out.println("登录的用户可以分享");
}
@Override
public void comment() {
System.out.println("登录的用户可以评论");
}
@Override
public void video() {
System.out.println("登录的用户看视频");
}
}
NewUserStates
public class NewUserStates implements UserStates {
@Override
public void share() {
System.out.println("没有登录的用户不可以分享");
}
@Override
public void comment() {
System.out.println("没有登录的用户不可以评论");
}
@Override
public void video() {
System.out.println("不登录的用户也可以看视频");
}
}
User
public class User {
private UserStates userStates = new NewUserStates();
/**
* 用户登录操作
*/
public void login(){
System.out.println("user 登录");
userStates = new LoginUserStates();
}
/**
* 用户退出操作
*/
public void exit(){
System.out.println("user 退出");
userStates = new NewUserStates();
}
/**
* 用户评论操作
*/
public void comment(){
userStates.comment();
}
/**
* 用户分享操作
*/
public void share(){
userStates.share();
}
/**
* 用户看视频操作
*/
public void video(){
userStates.video();
}
}
Client
public class Client {
public static void main(String[] args){
User user = new User();
user.video();
user.share();
user.comment();
user.login();
user.video();
user.share();
user.comment();
}
}
打印的log如下
状态模式的注意点
状态的转换
状态模式适用于对象在不同的状态下的的行为发生相应改变,即对象的所有行为存在着联系,即通过状态的这种方式去联系。所以在状态的切换的时候显得尤为重要,一般有两种方式去更改其状态,
1. 通过context类直接更改,对于上面的例子而言就是,user类,并且上述的例子就是通过这种方式去更改其状态的。这种更改方式使用存在联系的行为不会改变其状态。(share(),comment(),video()并不会改变其状态。)
2. 通过具体状态类去更改状态,这种方式一般发生在存在的联系的行为会更改状态,比如上面的不恰当的例子,用户分享后就会退出登录,需要重新登录,才能进行第二次分享。这个时候就需要将loginUserStates的share方法,之后加上将user中states切换成newUserStates.
两种方式,各有利弊,应该根据实际的情况去选择。
与策略模式的差异
其实上面的例子也可以通过策略模式去实现。但是仔细就会发生,其实并不算真正的策略模式,应该策略模式适用于对象的行为有多种不同的算法,不同行为的不同算法的实现类是平行关系,就是相互独立,彼此不会影响,但是状态的模式的对象行为之间是存在联系,也就意味着不同行为的不同实现方式是有联系,不能够任意替换。
状态模式的实用性
任何对象会发生状态改变,同时其行为发生改变的适用,
android
1. DataManager:remote和local,对数据的操作
2. 枚举常出现的地方。比如下载,
3. 用户登录系统
4. 跳转页面操作