相关阅读:
JAVA基础(一)简单、透彻理解内部类和静态内部类
JAVA基础(二)内存优化-使用Java引用做缓存
JAVA基础(三)ClassLoader实现热加载
HikariPool源码(二)设计思想借鉴枚举可以用来定义常量,也可以当作工厂类使用,其相比常量定义,定义可以更集中;相比工厂类,表达is A(某一种类型)的语义更强。
class Constants { // 常量定义方式一般通过相同前缀来分类,只要保证定义在同一个代码段就没问题,如果分散到多个代码段,找起来就挺费劲 public static final int SERV_TYPE_CAR = 1; public static final int SERV_TYPE_TV = 2; public static final int SERV_TYPE_MOBILE = 3; // 通过枚举定义的方式更加集中,不可能会分散到多个代码段 public enum SERV_TYPE { CAR, TV, MOBILE } } 复制代码
// 使用常量 public static void dox(int servType) { switch (servType) { case Constants.SERV_TYPE_CAR: // do something break; case Constants.SERV_TYPE_MOBILE: // do something break; case Constants.SERV_TYPE_TV: // do something break; default: break; } } // 使用枚举 public static void doy(Constants.SERV_TYPE servType) { switch (servType) { case CAR: // do something break; case TV: // do something break; case MOBILE: // do something break; default: break; } } 复制代码
可见,在使用上并无多大区别,仅仅是在定义时枚举定义能保证更加集中,好维护。
枚举充当工厂类的用法在很多开源项目中都可以看到,其作用和工厂类一样。先看下例子的类结构:
类 | 职责 |
---|---|
CacheType | 缓存类型,枚举类,通过它来获取对应的缓存类实例 |
BasicCache | 缓存类接口,对外暴露 |
ConcurrentMapCache | ConcurrentMap实现的缓存,可以不对外暴露 |
LinkedHashMapCache | LinkedHashMap实现的缓存,可以不对外暴露 |
public interface BasicCache<K, V> { V get(K key); void put(K key, V value); } 复制代码
// 注:没有public修饰,只在包内访问,屏蔽了可见性,对外只暴露BasicCache final class LinkedHashMapCache<K, V> implements BasicCache<K, V> { private final Map<K, V> map; public LinkedHashMapCache(int maximumSize, boolean accessOrder) { map = new BoundedLinkedHashMap<>(maximumSize, accessOrder); } @Override public V get(K key) { synchronized (map) { return map.get(key); } } @Override public void put(K key, V value) { synchronized (map) { map.put(key, value); } } static final class BoundedLinkedHashMap<K, V> extends LinkedHashMap<K, V> { private static final long serialVersionUID = 1L; private final int maximumSize; public BoundedLinkedHashMap(int maximumSize, boolean accessOrder) { super(maximumSize, 0.75f, accessOrder); this.maximumSize = maximumSize; } @Override protected boolean removeEldestEntry(Map.Entry<K, V> eldest) { return size() > maximumSize; } } } final class ConcurrentMapCache<K, V> implements BasicCache<K, V> { private final ConcurrentMap<K, V> map; public ConcurrentMapCache(ConcurrentMap<K, V> map) { this.map = requireNonNull(map); } @Override public V get(K key) { return map.get(key); } @Override public void put(K key, V value) { map.put(key, value); } } 复制代码
public enum CacheType { ConcurrentHashMap { @Override public <K, V> BasicCache<K, V> create(int maximumSize) { return new ConcurrentMapCache<>(new ConcurrentHashMap<>(maximumSize)); } }, LinkedHashMap { @Override public <K, V> BasicCache<K, V> create(int maximumSize) { return new LinkedHashMapCache<>(maximumSize, true); } }; public abstract <K, V> BasicCache<K, V> create(int maximumSize); } 复制代码
// 使用枚举,可充当工厂类作用 BasicCache<String, String> enumConcurrentHash = CacheType.ConcurrentHashMap.create(2); BasicCache<String, String> enumLinkedHash = CacheType.LinkedHashMap.create(2); 复制代码
可以看到,此时枚举类充当了工厂类的作用。
如果ConcurrentMapCache和LinkedHashMapCache定义为public的,那么可以直接实例化,如下:
BasicCache<String, String> concurrentMapCache = new ConcurrentMapCache<>(new ConcurrentHashMap<>(2)); BasicCache<String, String> linkedHashMapCache = new LinkedHashMapCache<>(2, true); 复制代码
既然可以直接实例化,为什么还需要通过枚举来创建实例? 其主要目的和工厂类一样:屏蔽创建类实例的逻辑,外部直接使用接口就好。
// 工厂类 public final class CacheFactory { public static BasicCache createConcurrentMapCache(int maximumSize) { return new ConcurrentMapCache<>(new ConcurrentHashMap<>(maximumSize)); } public static BasicCache createLinkedHashMapCache(int maximumSize) { return new LinkedHashMapCache<>(maximumSize, true); } } // 使用 BasicCache<String, String> concurrentHashCache = CacheFactory.createConcurrentMapCache(2); BasicCache<String, String> linkedHashCache = CacheFactory.createLinkedHashMapCache(2); 复制代码
从以上例子类看,枚举和工厂类用法并没有多大区别.