zoukankan      html  css  js  c++  java
  • 基于BIT数组实现全局功能开关

    前提

    某一天巧合打开了sofa-bolt项目,查找部分源码,看到了项目中使用bit数组实现功能开关的特性,感觉这种方式可以借鉴,于是写下这篇文章。

    原理

    bit数组的布局如下:

    由于每个bit都可以表示1或者0,刚好对应于开关的ONOFF。只需要定义好每个开关所在的bit数组下标和开关的状态(ON = 1或者OFF = 0),通过判断不同开关下标所在的bit即可判断开关的状态:

    • 优点:节省空间,理论上只需要占用最多2n位的内存(n为开关的数量,这里考虑扩容,扩容让bit数组长度为原来的2倍)
    • 缺点:暂时没发现

    实现

    JDK中的bit数组可以直接使用BitSet。首先定义开关定义SwitchDef

    public class SwitchConst {
    
        public static final boolean ON = true;
        public static final boolean OFF = false;
    }
    
    @RequiredArgsConstructor
    @Getter
    public enum SwitchDef {
    
        /**
         * 启用HTTPS
         */
        ENABLE_HTTPS(0, SwitchConst.ON, "启用HTTPS"),
    
        /**
         * 启用异步
         */
        ENABLE_ASYNC(1, SwitchConst.OFF, "启用异步"),
    
        ;
    
        /**
         * 下标
         */
        private final int index;
    
        /**
         * 默认状态
         */
        private final boolean defaultStatus;
    
        /**
         * 描述
         */
        private final String description;
    
        @Override
        public String toString() {
            return String.format("SwitchDef(name=%s,description=%s)", name(), description);
        }
    }
    

    接着定义开关接口Switch

    public interface Switch {
    
        /**
         * 启用
         *
         * @param switchDef switchDef
         */
        void turnOn(SwitchDef switchDef);
    
        /**
         * 关闭
         *
         * @param switchDef switchDef
         */
        void turnOff(SwitchDef switchDef);
    
        /**
         * 判断状态
         *
         * @param switchDef switchDef
         * @return boolean
         */
        boolean status(SwitchDef switchDef);
    }
    

    最后编写开关实现BitSetSwitch和客户端代码:

    public enum BitSetSwitch implements Switch {
    
        /**
         * 单例
         */
        X;
    
        BitSetSwitch() {
            init();
        }
    
        private final BitSet switches = new BitSet();
    
        @Override
        public void turnOn(SwitchDef switchDef) {
            switches.set(switchDef.getIndex(), SwitchConst.ON);
        }
    
        @Override
        public void turnOff(SwitchDef switchDef) {
            switches.clear(switchDef.getIndex());
        }
    
        @Override
        public boolean status(SwitchDef switchDef) {
            return switches.get(switchDef.getIndex());
        }
    
        private void init() {
            Stream.of(SwitchDef.values()).forEach(item -> switches.set(item.getIndex(), item.isDefaultStatus()));
        }
    
        public static void main(String[] args) {
            Switch s = BitSetSwitch.X;
            s.turnOn(SwitchDef.ENABLE_HTTPS);
            s.turnOff(SwitchDef.ENABLE_ASYNC);
            System.out.printf("开关[%s],状态:%s%n", SwitchDef.ENABLE_HTTPS, s.status(SwitchDef.ENABLE_HTTPS));
            System.out.printf("开关[%s],状态:%s%n", SwitchDef.ENABLE_ASYNC, s.status(SwitchDef.ENABLE_ASYNC));
        }
    }
    

    执行该main方法后控制台输出如下:

    开关[SwitchDef(name=ENABLE_HTTPS,description=启用HTTPS)],状态:true
    开关[SwitchDef(name=ENABLE_ASYNC,description=启用异步)],状态:false
    

    仿真场景(伪代码)如下:

    Switch s = BitSetSwitch.X;
    String uri = "www.throwx.cn";
    String schema = "http";
    if (s.turnOn(SwitchDef.ENABLE_HTTPS)){
        schema = "https";
    }
    HttpClint ch = new DefaultHttpClient();
    if (s.turnOn(SwitchDef.ENABLE_ASYNC)){
        ch = new AsyncHttpClient();
    }
    Result r = ch.executeRequest(schema + uri);
    ......
    

    小结

    在阅读一些主流框架源码的时候,可以借鉴一些设计合理的方案应用到自身的日常开发中。

    参考资料:

    (e-a-20210724 c-2-d)

  • 相关阅读:
    python面试的100题(2)
    面试题目和地址
    python面试的100题(1)
    no module named系列问题解决
    ubuntu16.04无法打开终端
    Reinforcement Learning,微信公众号:DRL学习
    Java中的I/O操作File
    Java中的Date时间转换【SimpleDateFormat (parse和format)】和Calendar日历表
    重写equals方法
    Java中栈,堆,常量池的简单理解
  • 原文地址:https://www.cnblogs.com/throwable/p/15083516.html
Copyright © 2011-2022 走看看