網頁

2019/2/1

Java bit flag

當要用一個值儲存多種狀態的時候,可以利用bit flag。


bit flag是指利用一個數值的二進位表示的0和1來代表狀態的開啟或關閉、存在或不存在。

通常都是用boolean來做flag。

boolean isVip; // true or false

但問題是boolean只能表示兩種狀態,若有多種狀態,就必須要有多個boolean變數來儲存。

而使用bit flag則只需要用一個數值變數即可儲存多種狀態。

Color.java

public class Color {

    // 二進位表示
    public static final int BLACK = 0b0001; // 1
    public static final int WHITE = 0b0010; // 2
    public static final int BLUE  = 0b0100; // 4
    public static final int RED   = 0b1000; // 8

    private int colors; // bit flag

    public int getColors() {
        return colors;
    }

    public void setColors(int colors) {
        this.colors = colors;
    }

    /** 是否有顏色 */
    public boolean hasColors() {
        return colors != 0;
    }

    /** 加入顏色 */
    public void addColors(int color) {
        colors |= color;
    }

    /** 移除顏色 */
    public void removeColors(int color) {
        colors &= ~color;
    }

    /** 是否為同顏色 */
    public boolean isColors(int colorMask) {
        return colors == colorMask;
    }

    /** 是否包含顏色 */
    public boolean isContainColors(int colorMask) {
        return (colors & colorMask) != 0;
    }

    /** 是否不包含顏色 */
    public boolean isNotContainColors(int colorMask) {
        return (colors & colorMask) == 0;
    }

}

上面的Color.colors即是big flag,可儲存多種顏色,並搭配位元遮罩bit mask即上面的colorMask及位元運算子來做各種操作。

public static void main(String[] args) {

    Color c = new Color();
    int colors = Color.BLUE;
    c.setColors(colors); // colors is BLUE

    System.out.println(c.isColors(Color.BLUE)); // true
    System.out.println(c.isContainColors(Color.RED | Color.BLUE)); // true

    c.addColors(Color.RED); // now colors is BLUE and RED
    System.out.println(c.isContainColors(Color.RED)); // true

    c.removeColors(Color.BLUE); // now colors is RED
    System.out.println(c.isContainColors(Color.BLUE)); // false

    c.addColors(Color.BLACK | Color.WHITE); // now colors is RED, BLACK, WHITE
    System.out.println(c.isContainColors(Color.WHITE)); // true

    c.removeColors(Color.RED | Color.BLACK | Color.WHITE);
    System.out.println(c.hasColors()); // false

    c.setColors(Color.WHITE | Color.BLACK); // now color is WHITE and BLACK
    System.out.println(c.isNotContainColors(Color.RED)); // true
    System.out.println(c.isNotContainColors(Color.RED | Color.WHITE)); // false

}

之前在某工作的產品也是這樣設計,該產品前端畫面有許多功能面板,而面板中又有許多功能,其透過在資料庫設定flag值來控制功能的開啟或關閉。系統啟動後會先去資料庫撈取flag的值,然後與應用層設定的各mask值做判斷來決定前端某功能的開啟或關閉。然而資料庫欄位使用bit flag儲存多種狀態的設計會讓程式變得難維護。例如在資料庫的設定功能的欄位`features`的值為33,很難知道這個值所代表的意思,即使有良好的文件說明仍要計算才能知道。

看了些文章big flag可以改用EnumSet<E extends Enum<E>>來實作。

如果本篇有幫助到您,幫忙點一下廣告支持,感恩。


沒有留言:

張貼留言