1.状态模式
状态模式State Pattern,是行为型设计模式。
状态模式指的是当一个对象的内在状态改变时,其行为也随之改变。即状态模式中的行为是由状态决定的,不同的状态下有不同的行为。
状态模式把对象的行为包装在不同的状态对象里,每一个状态对象都有一个共同的抽象状态基类。状态模式的意图是让一个对象在其内部状态改变的时候,其行为也随之改变。
状态模式和策略模式的机构几乎完全一样,但它们的目的、本质却完全不一样。状态模式的行为是平行的,不可替换的,但策略模式的行为是彼此独立、可相互替换的。
UML类图:
①Context:环境类,定义用户感兴趣的接口,维护一个State子类的实例,这个实例定义了对象的当前状态。
②State:抽象状态类或者状态接口,定义一个或者一组接口,表示该状态下的行为。也就是在这里定义各种行为方法。
③ConcreteStateA,ConcreteStateB:具体状态类,每一个具体的状态类实现抽象状态类中定义的接口,从而达到不同状态下的不同行为。具体状态类主要有两个职责,一是处理本状态下的事情,二是从本状态如何过渡到其他状态。
适用场景:
①一个对象的行为取决于它的状态,并且它必须在运行时刻根据状态改变它的行为。
②一个操作中含有庞大的多分支结构,并且这些分支决定于对象的状态。
优点:
①将繁琐的状态判断转换成结构清晰的状态类族,在避免代码膨胀的同时也保证了可扩展性和可维护性。
②体现了开闭原则和单一职责原则,每个状态都是一个子类,要增加状态只需增加子类,要修改状态只需修改一个子类即可。
③符合迪米特法则。
缺点:会增加系统类和对象的个数。
2.举例
比如一个app,它的状态有已登录和未登录两种。点击转发和评论按钮时,如果是已登录状态则可以跳转到转发、评论等页面,如果是未登录状态则跳转到登录界面。也就是说app的内部状态决定了转发和评论按钮的行为。
①定义状态接口,里面是按钮的各种操作行为
public interface UserState {
public void forward(Context context);//转发
public void comment(Context context);//评论
}
②具体的实现类--已登陆状态
public class LoginState implements UserState {
@Override
public void forward(Context context) {
Toast.makeText(context, "跳转到转发页", Toast.LENGTH_LONG).show();
}
@Override
public void comment(Context context) {
Toast.makeText(context, "跳转到评论页", Toast.LENGTH_LONG).show();
}
}
③具体的实现类--未登陆状态
public class LogoutState implements UserState {
@Override
public void forward(Context context) {
gotoLoginActivity(context);
}
@Override
public void comment(Context context) {
gotoLoginActivity(context);
}
private void gotoLoginActivity(Context context) {
Intent intent = new Intent(context, LoginActivity.class);
context.startActivity(intent);
}
}
④定义控制类接口
public interface ILoginContext {
public void loginState();
public void logoutState();
}
⑤实现控制类
public class LoginContext implements ILoginContext{
UserState userState = new LogoutState();//用户状态,默认为未登录状态
public void setUserState(UserState userState){
this.userState = userState;
}
@override
public void loginState(){
setUserState(new LoginState());
}
public void logoutState(){
setUserState(new LogoutState());
}
public void forward(Context context) {
userState.forward(context);
}
public void comment(Context context) {
userState.comment(context);
}
}
⑥客户端调用
LoginContext loginContext = new LoginContext();
loginContext.loginState();//设置为已登录状态
loginContext.forward();//跳到转发页面
loginContext.comment();//跳到评论页面
loginContext.logoutState();//设置为未登录状态
loginContext.forward();//跳到登录页面
loginContext.comment();//跳到登录页面
首先抽象了一个UserState接口,该接口中有用户可操作的所有行为。它有两个实现类,即已登录状态和未登录状态,已登录状态下点击转发和评论按钮可跳转到对应页面,关机状态下都跳到登录页面。app的内部状态影响了按钮的跳转行为。状态模式将这些行为封装到状态类中,在进行操作时将这些功能转发给状态对象,不同的状态有不同的实现,这样就通过多态的形式去除了重复的if-else语句,这也正是状态模式的精髓所在。
3.总结
状态模式的关键点在于不同的状态下对于同一行为有不同的响应,这其实就是一个将if-else用多态来实现的一个具体实例。在if-else或者switc-case形势下根据不同的状态进行判断,如果是A那么执行方法A,状态B执行方法B,但这种实现使得逻辑耦合在一起,易于出错,通过状态模式能够很好地消除这类“丑陋”的逻辑处理。