设计模式之----状态模式

友情提示:xmind导出的图片分辨率比较小,缩放查看。

这里写图片描述

一、定义

当一个对象在其内部状态改变的时候改变其行为。这个对象看上去就像是改变了它的类一样。又称状态对象模式,状态模式是对象的行为模式。

二、角色

  • 环境(Context)角色
    上下文:定义客户端所感兴趣的接口,并且保留一个具体状态类的实例。这个定义了对象的当前状态
  • 抽象状态(State)角色
    定义一个接口,用以封装环境(Context)对象的一个特定的状态所对应的行为(多种行为)。
  • 具体状态(ConcreteState)角色
    每一个具体状态类都实现了环境(Context)的一个状态所对应的行为。

三、使用场景

3.1 当一个对象的行为取决于它的状态,并且它必须在运行时刻根据状态改变它的行为时,就可以考虑使用状态模式来

3.2 一个操作中含有庞大的分支结构,并且这些分支决定于对象的状态。

状态模式将一个条件分支放入一个独立的类中,这使得你可以根据对象自身情况将对象的状态作为一个对象,这一对象可以不依赖于其他对象而独立变化,这样通过多态来去除过多的,重复的if-else等分支语句

四、需求

电视遥控器,分为开机和关机两种状态,在开机状态下可以通过遥控器进行频道切换,调整音量操作,但是开机键是无效的。在关机状态下 频道切换,调整音量,关机都是无效的。只有开机键是有效的

五、代码实现

5.1 普通代码实现

5.1.1 遥控器功能的实现
/**
 * 普通实现:电视遥控器
 *
 * Created by Administrator on 2017/10/28.
 */

public class TvControl {

    private static final String TAG = TvControl.class.getSimpleName();
    // 开机状态
    private static int POWER_ON = 1;
    // 关机状态
    private static int POWER_OFF = 2;

    private int mState = POWER_OFF;

    // 开机
    public void powerOn(){
        if (mState == POWER_OFF){
            Log.e(TAG,"开机了");
        }else{
            Log.e(TAG,"开机无效");
        }
        mState = POWER_ON;
    }
    // 关机
    public void powerOff(){
        if (mState == POWER_ON){
            Log.e(TAG,"关机了");
        }else{
            Log.e(TAG,"关机无效");
        }
        mState = POWER_OFF;
    }

    // 上一频道
    public void preChannel(){
        if (mState == POWER_ON){
            Log.e(TAG,"切换到上一个频道");
        }else{
            Log.e(TAG,"切换频道无效");
        }
    }
    // 上一频道
    public void nextChannel(){
        if (mState == POWER_ON){
            Log.e(TAG,"切换到下一个频道");
        }else{
            Log.e(TAG,"切换频道无效");
        }
    }
}
5.1.2 调用
// 普通方式
TvControl tvControl = new TvControl();
tvControl.powerOn();
tvControl.nextChannel();
tvControl.preChannel();
tvControl.powerOff();
tvControl.nextChannel();
tvControl.preChannel();
tvControl.powerOff();
tvControl.powerOn();
tvControl.powerOff();

运行结果:

10-28 02:55:39.325 2025-2025/com.statepattern E/TvControl: 开机了
10-28 02:55:39.325 2025-2025/com.statepattern E/TvControl: 切换到下一个频道
10-28 02:55:39.325 2025-2025/com.statepattern E/TvControl: 切换到上一个频道
10-28 02:55:39.325 2025-2025/com.statepattern E/TvControl: 关机了
10-28 02:55:39.325 2025-2025/com.statepattern E/TvControl: 切换频道无效
10-28 02:55:39.325 2025-2025/com.statepattern E/TvControl: 切换频道无效
10-28 02:55:39.325 2025-2025/com.statepattern E/TvControl: 关机无效
10-28 02:55:39.325 2025-2025/com.statepattern E/TvControl: 开机了
10-28 02:55:39.325 2025-2025/com.statepattern E/TvControl: 关机了

5.2 状态模式实现

5.2.1 抽象状态接口创建
/**
 *电视状态接口,定义了电视的操作方法
 *
 * Created by Administrator on 2017/10/28.
 */

public interface TvState {
    public static final String TAG = "TvState";
    public void powerOn();
    public void powerOff();
    public void prechannel();
    public void nextChannel();
}
5.2.2 具体的状态类实现
/**
 * 开机状态的具体操作
 *
 * Created by Administrator on 2017/10/28.
 */

public class PowerOnState implements TvState {

    @Override
    public void powerOn() {
        Log.e(TAG,"开机无效");
    }

    @Override
    public void powerOff() {
        Log.e(TAG,"关机了");
    }

    @Override
    public void prechannel() {
        Log.e(TAG,"切换到下一个频道");
    }

    @Override
    public void nextChannel() {
        Log.e(TAG,"切换到上一个频道");
    }
}
5.2.3 Context角色创建
/**
 * Context角色:电视遥控器
 *
 * Created by Administrator on 2017/10/28.
 */

public class TvContext {

    private TvState tvState = new PowerOffState();
    // 开机
    public void powerOn(){
        tvState.powerOn();
        tvState = new PowerOnState();
    }
    // 关机
    public void powerOff(){
        tvState.powerOff();
        tvState = new PowerOffState();
    }
    // 切换到上一频道
    public void preChannel(){
        tvState.prechannel();
    }
    //切换到下一频道
    public void nextChannel(){
        tvState.nextChannel();
    }
}
5.2.4 调用
TvContext tvContext = new TvContext();
tvContext.powerOn();
tvContext.nextChannel();
tvContext.preChannel();
tvContext.powerOff();
tvContext.nextChannel();
tvContext.preChannel();
tvContext.powerOff();
tvContext.powerOn();
tvContext.powerOff();

运行结果:

10-28 03:11:36.234 16021-16021/com.statepattern E/TvState: 开机了
10-28 03:11:36.234 16021-16021/com.statepattern E/TvState: 切换到上一个频道
10-28 03:11:36.234 16021-16021/com.statepattern E/TvState: 切换到下一个频道
10-28 03:11:36.234 16021-16021/com.statepattern E/TvState: 关机了
10-28 03:11:36.234 16021-16021/com.statepattern E/TvState: 切换频道无效
10-28 03:11:36.234 16021-16021/com.statepattern E/TvState: 切换频道无效
10-28 03:11:36.234 16021-16021/com.statepattern E/TvState: 关机无效
10-28 03:11:36.234 16021-16021/com.statepattern E/TvState: 开机了
10-28 03:11:36.234 16021-16021/com.statepattern E/TvState: 关机了

六、优缺点

6.1 优点

  1. 封装了转换规则。
  2. 枚举可能的状态,在枚举状态之前需要确定状态种类。
  3. 将所有与某个状态有关的行为放到一个类中,并且可以方便地增加新的状态,只需要改变对象状态即可改变对象的行为。
  4. 允许状态转换逻辑与状态对象合成一体,而不是某一个巨大的条件语句块
  5. 可以让多个环境对象共享一个状态对象,从而减少系统中对象的个数

6.2 缺点

  1. 状态模式的使用必然会增加系统类和对象的个数
  2. 状态模式的结构与实现都较为复杂,如果使用不当将导致程序结构和代码的混乱
  3. 状态模式对“开闭原则”的支持并不太好,对于可以切换状态的状态模式,增加新的状态类需要修改那些负责状态转换的源代码,否则无法切换到新增状态;而且修改某个状态类的行为也需修改对应类的源代码。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值