二十三、状态设计模式
23.1 状态设计模式简介
23.1.1 状态设计模式概述
状态设计模式(State Pattern):允许对象在内部状态发生改变时,改变他的行为,对象看起来好像修改了它的类;
状态模式中类的行为是由状态来决定的,在不同的状态下有不同的行为。其核心是让一个对象在其内部改变的时候,行为也随之改变。状态模式关注的核心点时将状态与行为进行绑定,不同的状态具备不同的行为;
【场景举例】
状态模式在我们生活中比较常见
- 例1:如某个社交网站中,普通用户的权限为发布文章、浏览文章、使用限定皮肤,而VIP用户可以发布付费文章、浏览付费资源、使用更加精美的皮肤;普通用户和VIP用户这就是两个状态,不同状态可以做的事情(行为)是不一样的;
- 例2:在网站中,未登录的用户可以浏览文章、查看评论等,登录过后的用户权限更加多,还可以点赞文章、收藏文章、发布评论等;登录的用户和未登录的用户就是两个状态,不同状态可以做的事情(行为)是不一样的;
状态模式要实现的就是一个操作一个对象时,其内部自动发生状态改变,看起来好像是修改了其他类一样;
23.1.2 状态设计模式的UML类图
状态设计模式中主要有3个角色:
- 1)环境角色(Context):也称为上下文,它定义了客户程序需要的接口,维护一个当前状态,并将与状态相关的操作委托给当前状态对象来处理。
- 2)抽象状态角色(State):定义一个接口,用以封装环境对象中的特定状态所对应的行为。
- 3)具体状态角色(ConcreteState):实现抽象状态所对应的行为。
23.2 状态设计模式的实现
【案例】
在网站中,未登录的用户可以浏览文章、查看评论等,登录过后的用户权限更加多,还可以点赞文章、收藏文章等;如果在未登录状态下点赞文章,一般网站会弹出登录框提醒用户登录,用户登录过后具备点赞文章、收藏文章等功能;
下面我们使用状态模式来实现上述案例;
- 1)抽象状态:
package com.pattern.demo01;
/**
* @author lscl
* @version 1.0
* @intro: 抽象状态
*/
public abstract class AbstractUserState {
protected Context context;
public void setContext(Context context) {
this.context = context;
}
// 点赞操作
public abstract void thumbup();
// 收藏操作
public abstract void favorite();
}
- 2)登录状态(具体状态):
package com.pattern.demo01;
/**
* @author lscl
* @version 1.0
* @intro: 具体状态
*/
public class LoginState extends AbstractUserState {
@Override
public void thumbup() {
System.out.println("点赞成功!");
}
@Override
public void favorite() {
System.out.println("收藏成功!");
}
}
- 3)未登录状态(具体状态):
package com.pattern.demo01;
/**
* @author lscl
* @version 1.0
* @intro:
*/
public class UnLoginState extends AbstractUserState {
@Override
public void thumbup() {
toLogin();
System.out.println("点赞成功!");
}
@Override
public void favorite() {
toLogin();
System.out.println("收藏成功!");
}
private void toLogin(){
System.out.println("欢迎来到登录页面!");
System.out.println("登录成功....");
// 将状态设置为登录状态
this.context.setState(this.context.LOGIN_STATE);
}
}
- 4)上下文角色:
package com.pattern.demo01;
/**
* @author lscl
* @version 1.0
* @intro: 上下文对象对具体的状态进行管理
*/
public class Context {
// 登录的状态
public static final AbstractUserState LOGIN_STATE = new LoginState();
// 未登录的状态
public static final AbstractUserState UNLOGIN_STATE = new UnLoginState();
// 当前状态(默认为未登录)
private AbstractUserState currentState = UNLOGIN_STATE;
{
// 初始化上下文
LOGIN_STATE.setContext(this);
UNLOGIN_STATE.setContext(this);
}
public void setState(AbstractUserState userState) {
this.currentState = userState;
this.currentState.setContext(this);
}
public void favorite() {
// 调用当前状态进行收藏
this.currentState.favorite();
}
public void thumbup() {
// 调用当前状态进行点赞
this.currentState.thumbup();
}
}
- 5)测试类:
package com.pattern.demo01;
/**
* @author lscl
* @version 1.0
* @intro:
*/
public class Demo01 {
public static void main(String[] args) {
// 创建上下文对象,包含多种状态
Context context=new Context();
// 使用上下文中的默认状态进行操作,如果发现当前状态不具备操作的权限将会自动切换状态,给用户感觉换了一个类一样
context.favorite();
context.thumbup();
}
}
23.3 状态设计模式的优缺点
- 优点:
- 1)将状态转换显示化:通常对象的状态都是通过赋值进行表现,不够直观。而使用状态类,当状态切换时,是以不同的类进行表示的,转换目的更加明确;
- 2)状态类职责明确,且具备扩展性;符合单一职责原则
- 缺点:
- 1)类膨胀:如果一类事物具备过多的状态,则会造成类的数量过多
- 2)虽然支持新增状态,这方面扩展性好;但是在新增状态时,需要修改原先状态切换部分的源码,否则状态也不能切换到新定义的状态,这方面扩展性差,不符合开闭原则;
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/131680.html