前提
某一天巧合開啟了sofa-bolt
專案,查詢部分原始碼,看到了專案中使用bit
陣列實現功能開關的特性,感覺這種方式可以借鑑,於是寫下這篇文章。
原理
bit
陣列的佈局如下:
由於每個bit
都可以表示1
或者0
,剛好對應於開關的ON
和OFF
。只需要定義好每個開關所在的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)