如何优雅地运用位运算实现产品需求

36次阅读

共计 3529 个字符,预计需要花费 9 分钟才能阅读完成。

原文地址:梁桂钊的博客

博客地址:http://blog.720ui.com

欢送关注公众号:「服务端思维」。一群同频者,一起成长,一起精进,突破认知的局限性。

如何优雅地使用位运算实现产品需要?

在开始注释之前,咱们先来说一下 Linux 的零碎权限设计。在 Linux 零碎中,为了保障文件的平安,对文件所有者、同组用户、其余用户的拜访权限进行了别离治理。其中,文件所有者,即建设文件或目录的用户。同组用户,是所属组群中的所有用户。其余用户,指的是既不是文件所有者,也不是同组用户的其余用户。每个文件和目录都具备读取权限、写入权限和执行权限,这三个权限之间互相独立。

在 Linux 零碎中,每个文件的拜访权限能够用 9 个字母示意,每 3 个字母示意一类用户权限,别离代表文件创建者、同组用户、其余用户。其中,r 示意读取权限,w 示意写入权限,x 示意执行权限。通过性能模式批改文件权限,有三个局部组成,包含对象、操作和权限。

假如须要减少同组用户写入权限,上面来看一个例子。

chmod g+w /root/install.log

此外,每一类用户的拜访也能够通过数字的形式进行示意。

那么,通过数字模式就能够对常见的 Linux 文件权限操作进行演绎。

假如须要设置创建者可读可写可执行、同组用户可读、其余用户可读,咱们能够这样写:

chmod 755 /root/install.log

事实上,Linux 的文件拜访权限就是十分经典的位运算应用场景。独一无二,咱们再来看下 Java 中的 java.lang.reflect.Modifier。其中,Modifier 类采纳 16 进制定义了动态常量。

public static final int PUBLIC           = 0x00000001;
public static final int PRIVATE          = 0x00000002;
public static final int PROTECTED        = 0x00000004;
public static final int STATIC           = 0x00000008;
public static final int FINAL            = 0x00000010;
public static final int SYNCHRONIZED     = 0x00000020;
public static final int VOLATILE         = 0x00000040;
public static final int TRANSIENT        = 0x00000080;
public static final int NATIVE           = 0x00000100;
public static final int INTERFACE        = 0x00000200;
public static final int ABSTRACT         = 0x00000400;
public static final int STRICT           = 0x00000800;
...

紧接着,Modifier 类提供了很多静态方法,例如 isPublic() 办法的返回值 & PUBLIC 对应的 16 进制值,如果非 0,则阐明含有 public 修饰符。

public static boolean isPublic(int mod) {return (mod & PUBLIC) != 0;
}

这里有一个重要的知识点,采纳 & 运算,两位同时为 1,后果才为 1,否则为 0。即 0&0=0; 0&1=0; 1&0=0; 1&1=1。例如:3&1  即 0000 0011 & 0000 0001 = 00000001,值为 1。

     0000 0011
&    0000 0001 
=    0000 0001  

与此同时,Modifier 类还采纳 | 运算,确保加入运算的两个对象只有有一个为 1,其值为 1。即 0|0=0;0|1=1;1|0=1;1|1=1。例如 Modifier.PUBLIC | Modifier.PROTECTED  | Modifier.PRIVATE | Modifier.ABSTRACT       | Modifier.STATIC | Modifier.FINAL | Modifier.STRICT 的后果是 3103,即 110000011111。

private static final int CLASS_MODIFIERS =
        Modifier.PUBLIC         | Modifier.PROTECTED    | Modifier.PRIVATE |
        Modifier.ABSTRACT       | Modifier.STATIC       | Modifier.FINAL   |
        Modifier.STRICT;

     0000 0000 0000 0001
|   0000 0000 0000 0010 
|   0000 0000 0000 0100 
|   0000 0000 0000 1000 
|   0000 0000 0001 0000 
|   0000 0100 0000 0000
|   0000 1000 0000 0000
=    0000 1100 0001 1111

书归正传,咱们站在前辈们的肩上,通过位运算设计优雅的多选标识,例如通过位运算实现权限管制或多状态治理,它的益处在于易扩大,防止数据库设计过程中字段收缩,缩小磁盘存储空间。

假如,咱们当初有一个有一个业务需要:在工作中增加一个告诉形式,可选项包含 IM 音讯、零碎揭示、邮箱、短信。抉择 IM 音讯后,反对 IM 即时发送;抉择零碎揭示后,反对站内信推送;抉择抉择邮箱后,该工作后续相干揭示内容,可通过发送邮件至相干人邮箱中进行告诉;抉择短信后,该工作后续相干揭示内容,可通过发送短信至相干人进行告诉。

咱们在设计数据库库表时,通常状况下,将多个标识字段合并成一个字段,并把这个字段改成字符串型形式保留,例如,存在 1 时示意反对 IM,2 时示意支持系统音讯,3 示意反对邮箱,4 示意反对短信。此时,如果同时都满足,它的存储模式就是以逗号分隔的字符串:“1,2,3,4”。这样设计的益处在于,不仅打消雷同字段的冗余,而且当减少新的渠道类别时,不需减少新的字段。

IM(1, "IM 音讯"),
SYSTEM(2, "零碎揭示"),
MAIL(3, "邮箱"),
SMS(4, "短信");

但在数据查问时,咱们须要对字符串进行分隔。并且字符串类型的字段在查问效率和存储空间上不如整型字段。因而,咱们能够用“位”来解决这个问题。咱们采取不同的位来别离示意不同类别的标识字段。

因而,当某个工作反对 IM 时,则保留 1(0000 0001);支持系统音讯时,则保留 2(0000 0010),反对邮箱时,则保留 4(0000 0100);反对短信时,则保留 8(0000 1000)。四种都反对,则保留 15(0000 11111)。

阐明
00000001 1 反对 IM
00000010 2 支持系统音讯
00000011 3 反对 IM、零碎音讯
00000100 4 反对邮箱
00000101 5 反对邮箱、IM
00000110 6 反对邮箱、零碎音讯
00000111 7 反对邮箱、IM、零碎音讯
00001000 8 反对短信
00001111 15 反对邮箱、IM、零碎音讯、短信

紧接着,咱们通过封装罕用办法来实现增删改。

/**
 * 判断
 * @param mod 用户以后值
 * @param value  须要判断值
 * @return 是否存在
 */
public static boolean hasMark(long mod, long value) {return (mod & value) == value;
}

/**
 * 减少
 * @param mod 已有值
 * @param value  须要增加值
 * @return 新的状态值
 */
public static long addMark(long mod, long value) {if (hasMark(mod, value)) {return mod;}
    return (mod | value);
}

/**
 * 删除
 * @param mod 已有值
 * @param value  须要删除值
 * @return 新值
 */
public static long removeMark(long mod, long value) {if (!hasMark(mod, value)) {return mod;}
    return mod ^ value;
}

总结一下,咱们在数据库设计时,将多个标识字段合并成一个字段,并把这个字段改成字符串型形式保留,不仅打消雷同字段的冗余,而且当减少新的渠道类别时,不需减少新的字段,然而字符串类型的字段在查问效率和存储空间上不如整型字段。因而,咱们能够参考用“位”来解决这个问题。咱们采取不同的位来别离示意不同类别的标识字段。

写在开端

【服务端思维】:咱们一起聊聊服务端核心技术,探讨一线互联网的我的项目架构与实战经验。让所有孤军奋战的研发人员都找到属于本人的圈子,一起交换、探讨。在这里,咱们能够认知降级,连贯顶级的技术大牛,连贯优良的思维形式,连贯解决问题的最短门路,连贯所有优良的办法,突破认知的局限。

更多精彩文章,尽在「服务端思维」!

本文由博客一文多发平台 OpenWrite 公布!

正文完
 0