一、背景
中间件的一些特征组合或者业务的某个字段是多个特征组合,如果直接用数字,组合较多保存非常复杂。
这里提供一个粗略的DEMO, 大家感兴趣可以参考改造。
二、源码
特征
public interface Feature {
/**
* 获取特性(掩码)
*/
int getMask();
/**
* 所有特性
*/
Feature[] listAll();
}特征工具类
public class FeatureUtil {
/**
* 此特性是否开启
*
* @param features 特性值
* @param feature 某个特性
* @return 是否开启
*/
public static boolean isEnabled(int features, Feature feature) {
return (features & feature.getMask()) != 0;
}
/**
* 配置某个特性
*
* @param features 特性值
* @param feature 某个特性
* @param state 是否开启
* @return
*/
public static int config(int features, Feature feature, boolean state) {
if (state) {
features |= feature.getMask();
} else {
features &= ~feature.getMask();
}
return features;
}
/**
* 开启某些特性的值
*
* @param features 特性数组
* @return 特性值
*/
public static int of(Feature... features) {
if (features == null) {
return 0;
}
return of(Stream.of(features).collect(Collectors.toSet()));
}
/**
* 开启某些特性的值
*
* @param features 特性数组
* @return 特性值
*/
public static int of(Set<Feature> features) {
if (features == null) {
return 0;
}
int value = 0;
for (Feature feature : features) {
value |= feature.getMask();
}
return value;
}
/**
* 判断特性值包含哪些特性
*
* @param features 特性值
* @param featureArray 特性数组
* @return 包含的特性
*/
public static Set<Feature> resolve(Integer features, Feature[] featureArray) {
if (featureArray == null) {
throw new IllegalArgumentException("特征数组不为null");
}
if (features == null || features == 0) {
return new HashSet<>(0);
}
Set<Feature> featureSet = new HashSet<>();
for (Feature feature : featureArray) {
if ((features & feature.getMask()) != 0) {
featureSet.add(feature);
}
}
return featureSet;
}
}枚举举例
public enum DemoEnum implements Feature {
FIRST("第一个"),
SECOND("第二个"),
THIRD("第三个");
DemoEnum() {
mask = (1 << ordinal());
}
DemoEnum(String desc) {
mask = (1 << ordinal());
this.desc = desc;
}
private final int mask;
private String desc;
@Override
public final int getMask() {
return mask;
}
@Override
public Feature[] listAll() {
return DemoEnum.values();
}
public String getDesc() {
return desc;
}
}测试类
public class FeatureUtilTest {
private int features;
@Before
public void init() {
features = FeatureUtil.of(DemoEnum.values());
}
@Test
public void isEnabled() {
boolean enabledFirst = FeatureUtil.isEnabled(features, DemoEnum.FIRST);
boolean enabledSecond = FeatureUtil.isEnabled(features, DemoEnum.SECOND);
Assert.assertTrue(enabledFirst);
Assert.assertTrue(enabledSecond);
}
@Test
public void config() {
int defaultFeature = 0;
int enableFirst = FeatureUtil.config(defaultFeature, DemoEnum.FIRST, true);
int enableFirst2 = FeatureUtil.of(DemoEnum.FIRST);
Assert.assertEquals(enableFirst, enableFirst2);
}
@Test
public void of() {
// 前两个特性
int two = FeatureUtil.of(DemoEnum.FIRST, DemoEnum.SECOND);
Assert.assertEquals(two, 3);
// 后两个特性
int lastTwo = FeatureUtil.of(DemoEnum.THIRD, DemoEnum.SECOND);
Assert.assertEquals(lastTwo, 6);
}
@Test
public void resolve() {
int features = FeatureUtil.of(DemoEnum.FIRST, DemoEnum.THIRD);
Set<Feature> resolve = FeatureUtil.resolve(features, DemoEnum.values());
Assert.assertEquals(resolve.size(), 2);
Assert.assertTrue(resolve.contains(DemoEnum.FIRST));
Assert.assertTrue(resolve.contains(DemoEnum.THIRD));
}
}三、解析
java.lang.Enum#ordinal 函数继承自枚举对象,获取该枚举值在枚举类中的排序,第一个为0,往后依次是1,2...。
这样不同的枚举通过左移进行区分,不同的特征组合通过 不同特征之间的按位与运算即可自由组合。
如特征1 + 特征4 则,两个特征的掩码 按位或即可。
如果取消某个特性,总特性值&=~某个性,让某个特性位置为0即可。
四、总结
由于枚举隐式继承了Enum类,因此如果想实现统一的方法,只能通过实现接口方式。
位运算的恰当使用可以将一些复杂逻辑简单化,可以非常容易得应对变化。
我们学习的时候,写代码的时候多去源码里看看,会有一些意外收获。
创作不易,如果觉得本文对你有帮助,欢迎点赞,欢迎关注我,如果有补充欢迎评论交流,我将努力创作更多更好的文章。
热门评论
-
秋田君2020-10-27 0
查看全部评论高级