一、背景
中间件的一些特征组合或者业务的某个字段是多个特征组合,如果直接用数字,组合较多保存非常复杂。
这里提供一个粗略的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类,因此如果想实现统一的方法,只能通过实现接口方式。
位运算的恰当使用可以将一些复杂逻辑简单化,可以非常容易得应对变化。
我们学习的时候,写代码的时候多去源码里看看,会有一些意外收获。
创作不易,如果觉得本文对你有帮助,欢迎点赞,欢迎关注我,如果有补充欢迎评论交流,我将努力创作更多更好的文章。
热门评论
高级