使用位运算进行状态管理

在稍微复杂的项目中,经常会遇到需要对当前业务场景进行状态判断的需求,并且这里的状态可能是多种状态组合的方式,可能只一种状态,也可能是多种状态共存。这里就可以借助位运算来解决,用一个整型数值上不同二进制位上的0、1数值来表示不同的状态。这样做既可以避免使用多个状态flag时重复if else逻辑判断,也有利于并发场景下状态更新和判断。在很多时候可以起到事半功倍的效果。这里就简单介绍如何进行状态设计和状态判断。

以淘宝app为例,可以看到在淘宝逛逛页面中,同时存在「关注」、「发现」、「视频」三个子tab,而在「发现」页面,同时存在「全部」、「玩乐」、「文创」、「家居」、「汽车」等子类目。当然在淘宝的实际业务中这些子类目应该是根据营销投放的数据接口动态配置类目名称和相关数据的,未必会有多状态管理的实际场景。这里只是以该页面结构作为演示,现在假设一种业务场景,需要判断是否是在「发现」->「玩乐」,如果是那就进行xxxx操作。
IMG_4889F4572496-1.jpeg
代码应该如何设计?这里推荐借助位运算,在同一个状态值上标记不同状态位的方式来进行状态管理。
1. 通过 << 定义数据的状态

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
static final int CONST_TAB = 0x00000001;
static final int CONST_FILTER = 0x000100;
// 关注
static final int TAB_FOLLOW = CONST_TAB << 0;
// 发现
static final int TAB_DISCOVER = CONST_TAB << 1;
// 视频
static final int TAB_VIDEO = CONST_TAB << 2;
// 2-全部
static final int MODEL_ALL = CONST_FILTER << 1;
// 2-玩乐
static final int MODEL_PLAY = CONST_FILTER << 2;
// 2-文创
static final int MODEL_CULTURAL = CONST_FILTER << 3;
// 2-家居
static final int MODEL_HOME = CONST_FILTER << 4;
// 2-汽车
static final int MODEL_CAR = CONST_FILTER << 5;

2. 通过 |= 加入多个状态

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 给当前状态添加指定的状态标记
static int addFlag(int model, int flag) {
return model | flag;
}

// 发现-全部
static final int FILTER_FOLLOW_DISCOVER_ALL = TAB_FOLLOW | MODEL_ALL;
// 发现-玩乐
static final int FILTER_FOLLOW_DISCOVER_PLAY = TAB_FOLLOW | MODEL_PLAY;
// 发现-文创
static final int FILTER_FOLLOW_DISCOVER_CULTURAL = TAB_FOLLOW | MODEL_CULTURAL;
// 发现-家居
static final int FILTER_FOLLOW_DISCOVER_HOME = TAB_FOLLOW | MODEL_HOME;
// 发现-汽车
static final int FILTER_FOLLOW_DISCOVER_CAR = TAB_FOLLOW | MODEL_HOME;

3.(m & STATUS) > 0 判断是否拥有该状态

1
2
3
4
5
6
7
8
9
10
// 判断当前状态model中是否存在状态标记
static boolean checkFlag(int model, int flag) {
return (model & flag) == flag;
}

int model = FILTER_FOLLOW_DISCOVER_ALL;
checkFlag(model, FILTER_FOLLOW_DISCOVER_PLAY);//false
checkFlag(model, TAB_FOLLOW);//true
checkFlag(model, TAB_DISCOVER);//false
checkFlag(model, MODEL_ALL);//true

4. (m & ~STATUS)扣除该状态

1
2
3
4
5
6
7
8
9
// 从当前状态中移除指定的状态标记
static int removeFlag(int model, int flag) {
return model & ~flag;
}

int model = FILTER_FOLLOW_DISCOVER_ALL;
model = removeFlag(model, MODEL_ALL);// 移除all状态
checkFlag(model, MODEL_ALL);//检查MODEL_ALL状态,false
checkFlag(model, TAB_FOLLOW);//检查TAB_FOLLOW状态,true

试想一下,如果不使用同一个状态值上不同状态位,而是使用多个状态值的组合来表示很多状态,那么在处理状态逻辑时就要使用很多if else嵌套语句来进行组合判断。
使用位运算可以极大减少代码量,让逻辑判断变得更清晰更简单。