在一个32位的计算机中,一个int型由4个字节,32个比特位组成。在日常使用中,一个int代表一个数字。在数据表中,可以代表某一事物或事件的一种状态。但这样未免太过单调。而且我们很难通过一个字段表示多种多种状态,且状态之间相互独立。即一个状态的改变不应该影响其他状态。比如,某个事件有A,B,C 三个状态。 可以发生的状态组合有A/B/C/AB/AC/BC/ABC。
方法1:如果用一个int类型的字段代表状态,我们可以通过 以下发送代表各种组合
A=1
B=2
C=3
AB=4
AC=5
BC=6
ABC=7
确实,上面是可以实现,但代码编写为变动非常复杂,比如
1.我要判断是否有C状态
if(status ==3 || status == 5 || status ==5 || status== 7)
2.撤销某个状态或者新增某个状态会变得复杂,我们必须知道当前的状态,然后才能进行撤销或者新增,比如新增C状态
if(status ==3 || status == 5 || status ==5 || status== 7) //已有C状态,直接返回
elseif(status=1){ status==xxx} 判断现在是什么状态,然后设置对应的值
elseif(status=2) {status==yy}
....
3. 如果这个事件新增加了状态C,D,F 那么复杂度会变得更恐怖。
方法2:通过多个int字段代码各种状态。
A,B,C各用一个字段表示,这样复杂度变的简单很多。同时不管设置状态还是撤销状态都会简单很多。但是也有个问题,如果新增了C,D,F状态就需要新增字段。并且虽然后期状态类型的增多,需要不断的添加为数据表添加字段。而这种行为是不建议的。
1.新增字段需要锁表,会影响服务,而且数量越多,影响时间越长
2.空间的浪费,如果有20状态,就需要 20个字段, 如果有N行数据,则共需要空间 20*4*N 个字节
方法3:通过bit占位表示各种状态。
一个int有32个比特位,那么就可以表示32种状态值。
用低四位分表示 :A,B,C,D,其余高28位用于备用
0000 无
0001 A
0010 B
0100 C
1000 D
设置状态:
原值status = 0
1.触发A: status=status|1 ->(0001)
2.触发B: status=status|2 ->(0011)
3.触发C: status=status|4 ->(0111)
4.触发D: status=status|8 ->(1111)
判断是否出现某种状态 :
A: status & 1(0001) == 1
B: status & 2(0010) == 2
C: status & 4(0100) == 4
D: status & 8(1000) == 8
撤销某状态:
A: status &16 (1110)
B: status &15 (1101)
C: status & 13(1011)
D: status & 7(0111)
对于新增一个状态, 原来的状态不需要变化,只需要增加一个标志位 0000 -> 00000,但对于撤销某种状态,增加一个标志位,会有影响,因此撤销标志位,应该通过调用特定函数,不应该零散的写在不同地方,避免增加标志位之后,出现大量修改。
比如调用如下代码进行状态撤销:
cancelStatus(22,2); //10110=22
//status 当前状态
//num: 撤销第N位状态
function cancelStatus($status,$num){
$bit = 5; //5个标志位
if($num>$bit || $num<1){
return false;
}
$max = pow(2,$bit)-1; //11111
$flag = pow(2,$num-1); //00010
$result = $max ^ $flag; //11101
$newstatus = $result & $status;
//do something
}
撤销某状态:
A: cancelStatus(status,1)
B: cancelStatus(status,2)
C: cancelStatus(status,3)
D: cancelStatus(status,4)
这样做的优缺点是:
1.编码逻辑变的简单
2.状态的增加,不需要新字段,不影响旧有逻辑,也不需要对原来的逻辑进行修改。只是需要修改cacelStatus 中的bit 尾数。做到最少修改
3.相比增加字段表示状态,这种方式更节省内存空间。
4.缺点是,二进制不太让人理解,不符合我们的常有思维
二进制除了上面的应用其实还有许多用处:
1.类型文件权限的读写及创建的控制
2. 2倍数的乘除法
3. 可以通过拆分高位,低位。用来表示不同状态或类型等。
如果网友有其他应用场景,可以留言,欢迎交流。