一句话说透Android里面的策略模式和状态模式的区别

153 阅读4分钟

一句话总结:
策略模式像「随时换刀」—— 不同算法灵活切换,状态模式像「自动档位」—— 行为随状态自动变化,Android 系统里两者各管一摊,一个拼工具,一个管流程!


一、策略模式(Strategy)—— 万能工具包

核心动态替换算法,把策略抽象成可插拔的模块
Android 源码例子:动画插值器 Interpolator

// frameworks/base/core/java/android/view/animation/Interpolator.java  
public interface Interpolator {  
    float getInterpolation(float input);  
}  

// 具体策略:线性插值  
public class LinearInterpolator implements Interpolator {  
    public float getInterpolation(float input) { return input; }  
}  

// 具体策略:弹性插值  
public class BounceInterpolator implements Interpolator {  
    public float getInterpolation(float input) { /* 弹性计算逻辑 */ }  
}  

// 使用方式:运行时切换策略  
ObjectAnimator anim = ObjectAnimator.ofFloat(view, "translationX", 0, 100);  
anim.setInterpolator(new BounceInterpolator()); // 换策略就像换工具  

底层原理

  • 动画系统通过 TimeInterpolator(即 Interpolator)接口分离算法
  • 运行时通过 setInterpolator() 动态改变插值策略

使用场景

  • 多种算法需要灵活切换(如加密算法、图片加载策略)
  • 需要隔离算法实现与使用者(如 RecyclerView 的布局管理器)

特点

  • 客户端主动选择策略
  • 策略之间彼此独立,无状态依赖

二、状态模式(State)—— 智能状态机

核心行为随状态自动改变,状态转换由内部逻辑驱动
Android 源码例子WifiManager 的状态管理

// frameworks/base/wifi/java/android/net/wifi/WifiManager.java  
private void updateState(int newState) {  
    synchronized (mLock) {  
        if (mWifiState != newState) {  
            mWifiState = newState;  
            // 状态变更触发行为  
            if (newState == WIFI_STATE_DISABLED) {  
                resetNotification();  
            } else if (newState == WIFI_STATE_ENABLED) {  
                checkAndSendScanAvailableBroadcast();  
            }  
        }  
    }  
}  

// 状态驱动的回调  
private void handleScanResultsAvailable() {  
    if (mWifiState != WIFI_STATE_ENABLED) return; // 行为受状态控制  
    // 执行扫描结果处理...  
}  

底层原理

  • 定义 WIFI_STATE_DISABLEDWIFI_STATE_ENABLED 等状态常量
  • 状态变更时自动触发关联操作(如广播通知、清理资源)

使用场景

  • 对象有多个状态且行为差异大(如播放器的播放/暂停/停止)
  • 状态转换逻辑复杂(如订单的待付款/已发货/已完成)

特点

  • 状态转换由对象内部管理
  • 不同状态对应不同行为实现

三、模式对比表

维度策略模式状态模式
核心目标灵活替换算法管理状态驱动的行为变化
变化触发方客户端主动设置对象内部状态自动触发
关注重点不同算法的实现状态转换逻辑和行为映射
Android案例Interpolator、LayoutManagerWifi 状态、MediaPlayer 生命周期
代码复杂度低(策略独立)高(需处理状态转换关系)

四、源码级原理剖析

1. 策略模式在 RecyclerView 布局的应用

// frameworks/base/core/java/androidx/recyclerview/widget/RecyclerView.java  
public void setLayoutManager(LayoutManager layout) {  
    mLayout = layout; // 动态切换布局策略  
    requestLayout();  
}  

// LinearLayoutManager(策略实现)  
public class LinearLayoutManager extends LayoutManager {  
    @Override  
    public void onLayoutChildren(Recycler recycler, State state) {  
        // 线性布局的具体算法  
    }  
}  

// GridLayoutManager(另一策略实现)  
public class GridLayoutManager extends LinearLayoutManager {  
    @Override  
    public void onLayoutChildren(Recycler recycler, State state) {  
        // 网格布局的具体算法  
    }  
}  
  • 客户端通过 setLayoutManager() 自由切换布局策略

2. 状态模式在 MediaPlayer 生命周期中的体现

// frameworks/base/media/java/android/media/MediaPlayer.java  
private int mCurrentState = IDLE; // 当前状态  

private void start() throws IllegalStateException {  
    if (mCurrentState != PREPARED) {  
        throw new IllegalStateException("prepare() must be called first");  
    }  
    // 开始播放...  
    mCurrentState = STARTED;  
}  

private void reset() {  
    // 重置时清理资源  
    if (mCurrentState == PLAYING) {  
        stop();  
    }  
    mCurrentState = IDLE;  
}  
  • 每个方法都检查当前状态,状态不符则抛出异常

五、使用场景口诀

算法多变用策略,状态驱动上状态

实际开发选择指南

  1. 图片加载库的缓存策略 → 策略模式(内存缓存、磁盘缓存灵活切换)
  2. 登录模块的验证方式 → 策略模式(短信、密码、指纹多种验证)
  3. 播放器控制 → 状态模式(播放、暂停、停止状态联动)
  4. 订单流程管理 → 状态模式(待支付、已发货、已完成状态转换)

注意事项

  1. 策略模式注意避免策略类膨胀(超过 5 个策略建议用工厂管理)
  2. 状态模式要确保状态转换的完整性(防止出现非法状态)
  3. 复杂状态机建议用状态表(二维数组表示状态转换规则)

六、逆向思维:如何区分两种模式?

问自己两个问题:

  1. 行为变化的原因是什么?

    • 如果是外部指定不同算法 → 策略模式
    • 如果是内部状态触发不同行为 → 状态模式
  2. 是否需要管理状态间的转换逻辑?

    • 不需要 → 策略模式
    • 需要 → 状态模式

经典误用案例
把网络重试机制(根据失败次数切换策略)硬写成状态模式,实际上更适合用策略模式 + 简单计数器


总结口诀
策略换算法,状态改行为
外选策略工具多,内变状态流程转