zoukankan      html  css  js  c++  java
  • 项目二进制标位实战应用

    四月已过大半,紧急补上一篇博客,本文将讲解二进制状态位在项目中的实战应用,技术原理很简单,就是利用二级制与位运算实现。这种方式的应用场景还是比较广泛,希望对你有用~

    本文首发于个人博客:http://nullpointer.pw/binary-tag.html

    前言


    举个栗子,需要保存这些状态你会怎么设计表呢?

    你可能会想,这很简单啊,针对一个开关加一个状态字段嘛~

    呵呵真是太年轻,这样开发上线后,产品又要增加新的提醒方式,如图

    难不成,再加状态字段?

    可以发现,以上这种做法,在需求改动时就会很蛋疼,而且这只是提醒的开关设置,若有其他类型的开关设置就更加麻烦。

    所以这里引入今天的主题,二进制状态位。

    二进制与位运算

    这样数据库只需要添加一个整数字段保存即可。使用2的次幂值代表一种状态,比如使用 1(2º) 代表开启站内提醒,2(2¹) 代表 开启邮件提醒,4(2²) 代表开启短信提醒等等,这样这个状态位字段只需要存储 6即可表示已开启这几项提醒。因为 6 与这几个状态值进行与运算时都等于状态值本身,如果不等于则为开启。

    首先回顾一下二进制与位运算的基础知识

    十进制 二进制
    0 0000 0000
    1 0000 0001
    2 0000 0010
    3 0000 0011
    4 0000 0100
    5 0000 0101
    6 0000 0110
    7 0000 0111

    或运算:bit位上有1为1。例如:2 | 1 == 0000 0010 | 0000 0001 == 3
    与运算:bit位都为1才为1。 例如 5 & 2 == 0000 0101 & 0000 0010 == 0

    实际应用

    以上文提醒开关为例:
    现在打开 站内提醒,不打开右键提醒,打开短信提醒,最终的值的计算方法为:
    1 | 4 = 5

    /**
     *  计算状态位
     *  tags: 已有状态位
     *  value: 需要添加的状态值
     */
    public static int addTag(int tags, int... values) {
      for (int value : values) {
        tags |= value;
      }
      return tags;
    }
    

    现在判断是否打开了站内提醒

    5 & 1 == 0000 0101 & 0000 0001 == 1

    /**
     *  是否包含状态位
     *  tags: 已有状态位
     *  value: 需要判断的状态值
     */
    public static boolean hasTag(int tags, int value) {
      return (tags & value) == value;
    }
    

    现在要关闭站内提醒

    5 ^ 1 == 0000 0101 ^ 0000 0001 == 4

    /**
      * 移除状态位
      * tags: 已有状态位
      * value: 需要移除的状态值
      */
    public static int delTag(int tags, int value) {
      if ((tags & value) != value) return tags;
      return tags ^ value;
    }
    

    测试:

    public static void main(String[] args) {
        int tag = addTag(0, 1, 4);
        System.out.println(tag); // 5
        System.out.println(hasTag(tag, 1)); // true
        System.out.println(hasTag(tag, 2)); // false
        System.out.println(hasTag(tag, 4)); // true
        tag = delTag(tag, 4);
        System.out.println(tag); // 1
        System.out.println(hasTag(tag, 4)); // false
    }
    

    使用优化

    在日常开发中,这些状态可以通过枚举值进行封装起来,方便使用。

    @Getter
    public enum NotifyTypeEnum {
        IN_MAIL(1, "站内信提醒", 1),
        EMAIL(2, "邮件提醒", 2),
        SMS(3, "短信提醒", 4),
        ;
    
        // 枚举值
        private Integer code;
        // 枚举描述
        private String desc;
        // 状态位
        private Integer tag;
    
        NotifyTypeEnum(Integer code, String desc, Integer tag) {
            this.code = code;
            this.desc = desc;
            this.tag = tag;
        }
    
        public boolean hasTag(int tags) {
            return (tags & this.tag) == tag;
        }
    
        public static void main(String[] args) {
            int tags = 5;
            System.out.println(NotifyTypeEnum.IN_MAIL.hasTag(tags)); // true
            System.out.println(NotifyTypeEnum.EMAIL.hasTag(tags)); // false
            System.out.println(NotifyTypeEnum.SMS.hasTag(tags)); // true
        }
    }
    

    参考

  • 相关阅读:
    容器操作--管理迭代器
    顺序容器--添加及访问元素
    日志记录-20151103
    顺序容器--容器库.迭代器
    使用-flat.vmdk恢复虚拟机
    H3C-交换机维护命令大全
    Centos6.5 安装zabbix-agent 3.0
    Linux系统调试工具之sysdig使用详解
    通过实例学习 tcpdump 命令
    系统之锹sysdig:Linux服务器监控和排障利器
  • 原文地址:https://www.cnblogs.com/vcmq/p/12813026.html
Copyright © 2011-2022 走看看