在日常开发过程中时常需要用到设计模式,但是设计模式有23种,如何将这些设计模式了然于胸并且能在实际开发过程中应用得得心应手呢?和我一起跟着《Android源码设计模式解析与实战》一书边学边应用吧!
设计模式系列文章
- Android 设计模式之单例模式
- Android 设计模式之Builder模式
- Android 设计模式之观察者模式
- Android 设计模式之代理模式
- Android 设计模式之装饰模式
- Android 设计模式之外观模式
- Android 设计模式之原型模式
- Android 设计模式之工厂方法模式
- Android 设计模式之策略模式
- Android 设计模式之适配器模式
- Android 设计模式之桥接模式
- Android 设计模式之面向对象的六大原则
今天我们要讲的是状态模式(State模式)
定义
当一个对象的内在状态改变时允许改变其行为,这个对象看起来像是改变了其类
使用场景
- 一个对象的行为取决于它的状态,并且它必须在运行时根据状态改变它的行为
- 代码中包含大量与对象状态有关的条件语句,例如,一个操作中含有庞大的多分支语句(if-else或switch-case),且这些分支依赖于该对象的状态
使用例子
- 最常见的应用是用户登录系统
实现
3大角色
- 环境类:定义客户端感兴趣的接口,维护一个抽象状态类的子类的实例,这个实例定义了对象当前状态
- 抽象状态类或状态接口:定义一个或一组接口,表示该状态下的行为
- 具体状态类:每个具体状态类实现抽象状态类中定义的接口,从而达到不同状态下的不同行为
实现的要点
- 把不同状态下的行为抽象成共同的接口到抽象状态类中
- 根据不同的状态,具体的状态类实现抽象状态类中的接口,从而实现不同的行为
- 环境类,也就是对外提供服务的类通过依赖抽象状态类来实现具体的行为,同时也达到与具体状态类的解耦
实现方式
下面我们以日常开发中的登录功能来简单应用下状态模式
- 在登录模块中一般我们会根据用户是否登录状态而有不同的操作,这里简单模拟2个操作,转发和评论
public interface UserState {
/**
* 转发
*
* @param context
*/
public void forward(Context context);
/**
* 评论
*
* @param context
*/
public void comment(Context context);
}
- 登录状态,调用转发和评论直接简单地弹出个Toast
public class LoginedState implements UserState {
@Override
public void forward(Context context) {
Toast.makeText(context, "转发成功", Toast.LENGTH_SHORT).show();
}
@Override
public void comment(Context context) {
Toast.makeText(context, "评论成功", Toast.LENGTH_SHORT).show();
}
}
- 未登录状态,调用转发和评论跳转到登录页面,这里直接简单地弹出登录的提示
public class LogoutState implements UserState {
@Override
public void forward(Context context) {
Toast.makeText(context, "未登录,跳转到登录页面", Toast.LENGTH_SHORT).show();
}
@Override
public void comment(Context context) {
Toast.makeText(context, "未登录,跳转到登录页面", Toast.LENGTH_SHORT).show();
}
}
- 根据不同的状态表现不一样的行为。下面我们看看对外提供服务的环境类
public class LoginContext {
/**
* 用户状态,默认为登录状态
*/
UserState userState = new LoginedState();
/**
* 单例
*/
static LoginContext loginContext = new LoginContext();
private LoginContext() {
}
public LoginContext getLoginContext() {
return loginContext;
}
public void setUserState(UserState userState) {
this.userState = userState;
}
public void forward(Context context) {
userState.forward(context);
}
public void comment(Context context) {
userState.comment(context);
}
}
- 以上的环境类的实现中,默认状态设置为登录状态,这个可以根据实际需要来定。下面我们看看怎么调用
//因为默认是登录状态,所以可以直接调用转发功能
LoginContext.getLoginContext().forward(MainActivity.this)
//注销登录,也就是登录状态改为未登录
LoginContext.getLoginContext().setUserState(new LogoutState());
//注销登录了以后再调用转发或是评论功能,执行的就会是弹出登录提示
LoginContext.getLoginContext().forward(MainActivity.this)
- 通过以上的例子我们就简单地实现了状态模式的应用啦
通过上面的例子我们可以看出,状态模式把对象的不同状态下的行为封装起来,并与对象的状态联系在一起。对象的状态改变了,对象的行为也会改变。在上面的例子中就是登录的状态LoginContext中的UserState状态不一样,执行的行为,比如转发功能就不一样
状态模式和策略模式
状态模式和策略模式的结构几乎完全一样,但它们的目的、本质却完全不一样。状态模式的行为是平行的、不可替换的,策略模式的行为是彼此独立、可相互替换的。用一句话来表述,状态模式把对象的行为包装在不同的状态对象里,每一个状态对象都有一个共同的抽象状态基类。状态模式的意图是让一个对象在其内部状态发生改变的时候,其行为也随之改变
总结
- 状态模式的关键点在于不同的状态下对于同一行为有不同的响应,这其实就是一个将if-else用多态来实现的具体实例
- 状态模式将所有与一个特定状态相关的行为都放入一个状态对象中,它提供了一个更好的方法来组织与特定状态相关的代码,将繁琐的状态判断转换成结构清晰的状态类族,在避免代码膨胀的同时也保证了可扩展性和可维护性
欢迎关注我的微信公众号,期待与你一起学习,一起交流,一起成长!