使用位屏蔽将启用了应用程序的功能存储到数据库中

时间:2018-08-22 09:57:47

标签: java

我想将许多应用程序功能存储到数据库中。我想为此使用一个表行,因此我想使用位掩码来存储已启用的功能。我尝试过:

HashMap<String, Integer> map = new HashMap<String, Integer>();
int database_value = 0; 

public int setFeatureBitmask(int value) {
    int bitmask = 0;
    bitmask |= value;       
    return bitmask;
}

public static Set<String> processFeature(Integer bitmask) {
    HashMap<String, Integer> newMap = new HashMap<String, Integer>();

    return newMap.entrySet().stream().filter(e -> (e.getValue() & bitmask) == e.getValue()).map(e -> e.getKey())
            .collect(Collectors.toSet());
}

@BeforeAll
public void setupData() {
    System.out.println("Populating settings map");

    map.put("Type1", 1);
    map.put("Type2", 2);
    map.put("Type3", 4);
    map.put("Type4", 8);
    map.put("Type5", 16);
    map.put("Type6", 32);
    map.put("Type7", 64);
    map.put("Type8", 128);
    map.put("Type9", 256);
    map.put("Type10", 512);
    map.put("Type11", 1024);
    map.put("Type12", 2048);
    map.put("Type13", 4096);
    map.put("Type14", 8192);
    map.put("Type15", 16384);
    map.put("Type16", 32768);
    map.put("Type17", 65536);
    map.put("Type18", 131072);
    map.put("Type19", 262144);
}

@Test
public void writeData() {
    System.out.println("Converting Map using bitmasking");

    for(int i=0; i<map.size(); i++) {

        int number_value = map.get(i);                      
        int result = setFeatureBitmask(number_value);           
        database_value = database_value + result;
    }       
}

@AfterAll
public void databaseInsert() {
    System.out.println("Final resut to insert into Database " + database_value);

    System.out.println("Converting back values from database");

    // read here values from database_value variable and convert them into hash     
}

第一个问题是如何将转换后的数字存储为一个大表值,例如15990793?我应该将所有转换后的数字合并为一个大数字吗? 而且在我转换了它们之后,如何再次翻译它们以便可以使用它们?

有没有可行的例子?我发现了很多掩码示例,但没有什么比我的情况更有效。尚不清楚如何获得工作结果,您可以提出建议吗?

编辑:

我对此进行了测试:

import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Map.Entry;

import org.junit.FixMethodOrder;
import org.junit.jupiter.api.Test;
import org.junit.runners.MethodSorters;

@FixMethodOrder(MethodSorters.DEFAULT)
public class DatabaseFeaturesTest {

    int opts = 0;
    Map<Feature, Boolean> features = new HashMap<Feature, Boolean>();
    Map<Feature, Boolean> featureMaps = new HashMap<Feature, Boolean>();

    public void enableFeature(Feature feature) {
        opts = opts | feature.getValue(); // Or regular sum
    }

    public void disableFeature(Feature feature) {
        opts = opts & (~feature.getValue());
    }

    public boolean isFeatureEnabled(Feature feature) {
        return (opts & feature.getValue()) != 0;
    }

    @Test
    public void firstTest() {
        System.out.println("Producing Features ");

        features.put(Feature.A, true);
        features.put(Feature.B, false);
    }

    @Test
    public void secondTest() {
        System.out.println("Converting Features for storage into Database");

        int opts = features.entrySet().stream().filter(Entry::getValue)
                .mapToInt(e -> e.getKey().getValue())
                .sum();

        System.out.println("produced value " + opts);
    }

    @Test
    public void thirdTest() {
        System.out.println("Reading from database ");

        Map<Feature, Boolean> featureMaps = 
                   Arrays.stream(Feature.values())
                         .collect(toMap(f -> f, 
                                        f -> (optsFromDatabase & f.getValue()) != 0,
                                        (v1, v2) -> v2,
                                        LinkedHashMap::new));
    }

    @Test
    public void fourthTest() {

        Boolean feature1 = featureMaps.get(Feature.A);
        Boolean feature2 = featureMaps.get(Feature.B);
        System.out.println("Reading from database Feature A " + feature1);
        System.out.println("Reading from database Feature A " + feature2);
    }
}

enum Feature {
    A("Type1", 1), // 1 << 0
    B("Type2", 2), // 1 << 1
    C("Type3", 4), // 1 << 2,
    F("Type6", 32); // 1 << 5

    private final String featureName;
    private final int value;

    private Feature(String featureName, int value) {
        this.featureName = featureName;
        this.value = value;
    }

    public String getFeatureName() {
        return featureName;
    }

    public int getValue() {
        return value;
    }
}

但是对于toMap我得到The method toMap((<no type> f) -> {}, (<no type> f) -> {}, (<no type> v1, <no type> v2) -> {}, LinkedHashMap::new) is undefined for the type DatabaseFeaturesTest

1 个答案:

答案 0 :(得分:0)

我不喜欢使用随机常数来表达特征。

首先将您的功能包装到一个枚举中:

public enum Feature {
     A("Type1", 1), // 1 << 0
     B("Type2", 2), // 1 << 1
     C("Type3", 4), // 1 << 2,
     ...
     F("Type6", 32); // 1 << 5

     private final String featureName;
     private final int value;

     // Constructor, getters/setters
}

假设您有变量int opts = 0来存储功能组合。

现在要启用一项功能:

public void enableFeature(Feature feature) {
    opts = opts | feature.getValue(); // Or regular sum
}

要禁用功能,请执行以下操作:

public void disableFeature(Feature feature) {
    opts = opts & (~feature.getValues());
}

要测试功能是否启用:

public boolean isFeatureEnabled(Feature feature) {
    return (opts & feature.getValue()) != 0;
}

要将Map<Feature, Boolean> features转换为组合整数:

int opts = features.entrySet().stream().filter(Entry::getValue)
                   .mapToInt(e -> e.getKey().getValue())
                   .sum();

现在,您将opts作为常规整数存储到数据库中。

要读回去:

final int optsFromDatabase = ....; // Read that combination value from DB

Map<Feature, Boolean> featureMaps = 
       Arrays.stream(Feature.values())
             .collect(toMap(f -> f, 
                            f -> (optsFromDatabase & f.getValue()) != 0,
                            (v1, v2) -> v2,
                            LinkedHashMap::new));

您将像下面那样恢复功能状态

{A=true, B=false, C=false, D=true, E=false, F=false ...}

更新

要支持许多功能(例如约100个功能),您应该坚持使用String。

现在,您应该稍微修改Feature类:

public enum Feature {
     A("Type1", 0), // index 0 in bit string
     B("Type2", 1), // index 1 in bit String
     C("Type3", 2), // index 2 in bit String
     ...
     Z("TypeZ", 100); // index 100 in bit String

     private final String featureName;
     private final int index;
}

现在将您的Map<Feature, Boolean>转换为位字符串:

public String convertToDatabaseValue() {
    return Arrays.stream(Feature.values()).map(f -> isFeatureEnabled(f) ? "1" : "0").collect(joining());
}

public Map<Feature, Boolean> initFromDatabaseValue(String bitString) {
    // Note that, bitString length should equals to your number of feature. Or you have to padding it
    char[] bitArray = bitString.toCharArray();
    return Arrays.stream(Feature.values())
            .collect(toMap(f -> f,
                    f -> bitArray[f.getIndex()] == '1',
                    (v1, v2) -> v2,
                    LinkedHashMap::new));
}