今天OA系统需要修改需求,之前的一个人员只能有一个职位的实现不能满足需求,要改为一个人可以同时具有多个职位。
之前职员的post的职位是使用enum实现的:
1 | public Enum Post{ |
新需求将添加与项目相关的职位,例如组长,总共。类似”副院长”同时又是”总工”。
其数据库底层是使用int类型的变量进行存储的。
虽然说enum一次只能有一个值,但是还是能通过一些“技巧”来实现一个人多种职位,那就是位掩码。
在维基百科上,对位掩码的定义是这样的:
“在计算机学科及数字逻辑中指的是一串二进制数字,通过与目标数字的按位操作,达到屏蔽指定位而实现需求”
比如对于一个八位二进制数:
00101110
我想要它的前四位,那么只需要这样与掩码进行与运算即可:
00101110&11110000 = 00100000
这其实就像是linux的文件权限一样。“755”
因为是位的运算,你一定可以肯定7表示4+2+1,你也可以通过7&4的结果是不是0,来判断是否包含这一位。
所以我们将使用2^n来重新实现Enum Post:
0001
0010
0100
1000
好吧,下面是新版本的(加入组长和总共)
1 | public Enum PostType{ |
那么就可以这样为其赋值:
1 | Post = int(PostType.Keyuan + PostType.ZuZhang) |
显然这种写法显得太蠢了,优化一下:
1 | public bool HasPost(PostType post){ |
这里有一个小细节很有趣,如果是做过嵌入式的人一定会用这种写法,而不是Post & post == post.
因为对于于运算,判断是否为0,要比判断相等快很多,因为就算是判断相等,也要先用减法,再判断是否为零。
这样我们就可以为一个员工添加多种Post了。
后记
其实这里还发生了一些有趣的事。
因为要对数据库中职位原来的字段进行更新替换,所以我一开始写下一张替换表,对数据库直接更新。
1 --> 1
2 --> 2
3 --> 4
4 --> 8
5 --> 16
6 --> 32
7 --> 64
但是如果直接通过这张表用 update 语句去更新数据库是有问题的。
因为在你执行 update set post = 8 where post = 4
时,除了旧的4,还有一部分新4,这时所有的4就都被替换了。
同理还有旧8和新8。
一个比较巧妙的做法是将这些sql语句倒着写。