前提

某一天巧合打开了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)

基于BIT数组实现全局功能开关的更多相关文章

  1. 基于STC12C5A的MINI3216多功能点阵时钟

    代码地址如下:http://www.demodashi.com/demo/12862.html 基于STC12C5A的MINI3216多功能点阵时钟 硬件详解 PCB 硬件原理图 主控模块 max72 ...

  2. 微软Azure配置中心 App Configuration (二):Feature Flag 功能开关特性

    写在前面 Web服务开发过程中我们经常有这样的需求: 某些功能我必须我修改了配置才启用,比如新用户注册送券等: 某个功能需到特定的时间才启用,过后就失效,比如春节活动等: 某些功能,我想先对10%的用 ...

  3. 基于90nm CMOS技术的功能齐全的64Mb DDR3 STT-MRAM

    自旋转矩磁阻随机存取存储器(ST-MRAM)有望成为一种快速,高密度的非易失性存储器,可以增强各种应用程序的性能,特别是在用作数据存储中的非易失性缓冲器时设备和系统.为此,everspin开发了基于9 ...

  4. [python] A*算法基于栅格地图的全局路径规划

    # 所有节点的g值并没有初始化为无穷大 # 当两个子节点的f值一样时,程序选择最先搜索到的一个作为父节点加入closed # 对相同数值的不同对待,导致不同版本的A*算法找到等长的不同路径 # 最后c ...

  5. 科学计算三维可视化---Mlab基础(基于Numpy数组的绘图函数)

    Mlab了解 Mlab是Mayavi提供的面向脚本的api,他可以实现快速的三维可视化,Mayavi可以通过Mlab的绘图函数对Numpy数组建立可视化. 过程为: .建立数据源 .使用Filter( ...

  6. 从头认识java-14.4 Java提供的数组的有用功能(2)

    接着上一章节,我们继续介绍Java提供的数组的有用功能. 3.元素的对照Comparator package com.ray.ch14; import java.util.Arrays; import ...

  7. php基于SQLite实现的分页功能示例

    php基于SQLite实现的分页功能. 这里操作数据库文件使用的是前面文章<PHP基于PDO实现的SQLite操作类>中的SQLite数据库操作类. 代码: <?php class ...

  8. 如何在 Blazor WebAssembly中 使用 功能开关

    微软Azure 团队开发的 功能管理 (Feature Management) 包 Microsoft.FeatureManagement可用于实现 功能开关,可以通过 功能开关 特性动态的改变应用程 ...

  9. HMS Core积极探索基于硬件耳返的功能,帮助唱吧整体唱歌延迟率降低60%

    唱吧的使命是让唱歌更简单.让生活更美好,其布局的K歌业务专注于让曲库更全.音质更好,开创了同框合唱.弹唱等有意思的游戏类K歌玩法.为了让用户拥有更加沉浸的娱乐体验,唱吧与HMS Core积极探索基于硬 ...

随机推荐

  1. 【疑难杂症】高版本UG从老UI中获取汉字字符串后乱码的问题

    结论:NXstring转换为char类型的时候导致了乱码 措施: 改前:string strA=Test001::test001StrName->ItemValue().GetText(); / ...

  2. 有模有样解决Flutter里Webview无法访问HTTP页面的问题

    探索过程 Android9(好像是吧)开始谷歌就默认不让开发者访问不安全HTTP内容了,如果非要用HTTP,那必须在networkSecurityConfig里配置cleartextTrafficPe ...

  3. Terraform模块Module管理,聚合资源的抽取与复用

    我最新最全的文章都在南瓜慢说 www.pkslow.com,欢迎大家来喝茶! 1 简介 最近工作中用到了Terraform,权当学习记录一下,希望能帮助到其它人. Terraform系列文章如下: T ...

  4. IDEA搭建一个SpringBoot项目——十分详细(web+mysql)

    ​前排提示: IDEA版本:IntelliJ IDEA 2021.1.1 专业版(是否为专业版影响不大) 搭建目的:前端web页面能够获取到MySQL数据库中的数据 详细步骤: 1. 创建一个新项目 ...

  5. .Net Core Host 之详解

    简介: 开发使用有三年经验了,想趁这个机会把net core的知识点梳理一下,也更好的研究一下.NET 5给我们带来的变化. 主机的概念: 一个主机是封装了应用程序的资源,比如一个对象: 依赖注入 ( ...

  6. 955.WLB 不加班公司名单!再新增 5 家公司!

    大家好!我是<Visual Studio Code 权威指南>的作者韩骏.相信不少童鞋都是因为 VS Code 认识到我:也许是用了我写的 20 多个 VS Code 插件(比如 Code ...

  7. 重新整理 .net core 实践篇————网关[三十六]

    前言 简单整理一下网关. 正文 在介绍网关之前,介绍一下BFF,BFF全称是Backend For Frontend,它负责认证授权,服务聚合,目标是为前端提供服务. 说的通透一点,就是有没有见过这种 ...

  8. css角标

    HTML: <div class='card-wrap'> <div class='news1'> <div class='ribbon'> <div cla ...

  9. Linux使用shell脚本监控

    (1)性能监控脚本 performance.sh #!/bin/bash #-------------------------------------------------------------- ...

  10. mybatis框架的第二天

    一.mybatis的基础crud的操作 先在接口中,写对应的方法名称,返回类型,访问符. 之后在映射配置文件中,写具体的实现 二.mybati中crud的细节 1.模糊查询 这是接口中 这是xml中 ...