前提

某一天巧合打開了sofa-bolt專案,查詢部分原始碼,看到了專案中使用bit陣列實現功能開關的特性,感覺這種方式可以借鑑,於是寫下這篇文章。

原理

bit陣列的佈局如下:

由於每個bit都可以表示1或者0,剛好對應於開關的ONOFF。只需要定義好每個開關所在的bit陣列下標和開關的狀態(ON = 1或者OFF = 0),通過判斷不同開關下標所在的bit即可判斷開關的狀態:

  • 優點:節省空間,理論上只需要佔用最多2n位的記憶體(n為開關的數量,這裡考慮擴容,擴容讓bit陣列長度為原來的2倍)
  • 缺點:暫時沒發現

實現

JDK中的bit陣列可以直接使用BitSet。首先定義開關定義SwitchDef

  1. public class SwitchConst {
  2. public static final boolean ON = true;
  3. public static final boolean OFF = false;
  4. }
  5. @RequiredArgsConstructor
  6. @Getter
  7. public enum SwitchDef {
  8. /**
  9. * 啟用HTTPS
  10. */
  11. ENABLE_HTTPS(0, SwitchConst.ON, "啟用HTTPS"),
  12. /**
  13. * 啟用非同步
  14. */
  15. ENABLE_ASYNC(1, SwitchConst.OFF, "啟用非同步"),
  16. ;
  17. /**
  18. * 下標
  19. */
  20. private final int index;
  21. /**
  22. * 預設狀態
  23. */
  24. private final boolean defaultStatus;
  25. /**
  26. * 描述
  27. */
  28. private final String description;
  29. @Override
  30. public String toString() {
  31. return String.format("SwitchDef(name=%s,description=%s)", name(), description);
  32. }
  33. }

接著定義開關介面Switch

  1. public interface Switch {
  2. /**
  3. * 啟用
  4. *
  5. * @param switchDef switchDef
  6. */
  7. void turnOn(SwitchDef switchDef);
  8. /**
  9. * 關閉
  10. *
  11. * @param switchDef switchDef
  12. */
  13. void turnOff(SwitchDef switchDef);
  14. /**
  15. * 判斷狀態
  16. *
  17. * @param switchDef switchDef
  18. * @return boolean
  19. */
  20. boolean status(SwitchDef switchDef);
  21. }

最後編寫開關實現BitSetSwitch和客戶端程式碼:

  1. public enum BitSetSwitch implements Switch {
  2. /**
  3. * 單例
  4. */
  5. X;
  6. BitSetSwitch() {
  7. init();
  8. }
  9. private final BitSet switches = new BitSet();
  10. @Override
  11. public void turnOn(SwitchDef switchDef) {
  12. switches.set(switchDef.getIndex(), SwitchConst.ON);
  13. }
  14. @Override
  15. public void turnOff(SwitchDef switchDef) {
  16. switches.clear(switchDef.getIndex());
  17. }
  18. @Override
  19. public boolean status(SwitchDef switchDef) {
  20. return switches.get(switchDef.getIndex());
  21. }
  22. private void init() {
  23. Stream.of(SwitchDef.values()).forEach(item -> switches.set(item.getIndex(), item.isDefaultStatus()));
  24. }
  25. public static void main(String[] args) {
  26. Switch s = BitSetSwitch.X;
  27. s.turnOn(SwitchDef.ENABLE_HTTPS);
  28. s.turnOff(SwitchDef.ENABLE_ASYNC);
  29. System.out.printf("開關[%s],狀態:%s%n", SwitchDef.ENABLE_HTTPS, s.status(SwitchDef.ENABLE_HTTPS));
  30. System.out.printf("開關[%s],狀態:%s%n", SwitchDef.ENABLE_ASYNC, s.status(SwitchDef.ENABLE_ASYNC));
  31. }
  32. }

執行該main方法後控制檯輸出如下:

  1. 開關[SwitchDef(name=ENABLE_HTTPS,description=啟用HTTPS)],狀態:true
  2. 開關[SwitchDef(name=ENABLE_ASYNC,description=啟用非同步)],狀態:false

模擬場景(虛擬碼)如下:

  1. Switch s = BitSetSwitch.X;
  2. String uri = "www.throwx.cn";
  3. String schema = "http";
  4. if (s.turnOn(SwitchDef.ENABLE_HTTPS)){
  5. schema = "https";
  6. }
  7. HttpClint ch = new DefaultHttpClient();
  8. if (s.turnOn(SwitchDef.ENABLE_ASYNC)){
  9. ch = new AsyncHttpClient();
  10. }
  11. Result r = ch.executeRequest(schema + uri);
  12. ......

小結

在閱讀一些主流框架原始碼的時候,可以借鑑一些設計合理的方案應用到自身的日常開發中。

參考資料:

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