难道我们日常使用的枚举还有什么特殊的玩法不成?没错,还真有,本文主要介绍枚举的两种不那么常见的使用姿势
- 利用枚举来实现单例模式
- 利用枚举来实现策略模式
1. 单例模式
单例模式可以说是每个 java 开发者必须掌握的一个设计模式了,通常我们说它的实现,有饱汉式和饿汉式,也有经常说的双重判断,今天我们介绍另外一种方式,借助枚举来实现
public enum SingleEnum { INSTANCE; public void print(String word) { System.out.println(word); } } @Test public void testSingle() { SingleEnum.INSTANCE.print("hello world"); } 复制代码
使用枚举来实现单例模式非常非常简单,将类声明为枚举,内部只定义一个值即可
为什么可以这样做?
- 枚举类不能
new
,因此保证单例 - 枚举类不能被继承
- 类不加载时,不会实例化
使用枚举类创建的单例有一个好处,就是即使用反射,也无法打破它的单例性质,这是相比较于其他的实现方式的一个优点
那么,为啥在实际的项目中,不太常见这种写法?
- 就我个人的一点认知(不保证准确):这个与我们对枚举的认知有一定关系,在 《Effect in java》一书中,推荐我们使用这种方式来实现单例,但是在实际的项目开发中,我们更多的将枚举作为常量来使用,很少在枚举类中,添加复杂的业务逻辑
2. 策略模式
枚举除了很容易就实现上面的单例模式之外,还可以非常简单的实现策略模式
举一个简单的例子,我现在有一个接口,通过接受的参数,来决定最终的数据存在什么地方
如果按照正常的写法,可能就是很多的 if/else
public void save(String type, Object data) { if ("db".equals(type) { // 保存到db saveInDb(data); } else if ("file".equals(type)) // 保存在文件 saveInFile(data); } else if ("oss".eqauls(type)) { // 保存在oss saveInOss(type); } } 复制代码
上面这种写法虽说简单直观,但是当 type 类型一多了之后,这个 if/else 的代码行数就会很多很多了,而且看起来也不美观
接下来我们介绍一种利用枚举,基于策略模式的思想来解决上面的 if/else 问题
public enum SaveStrategyEnum { DB("db") { @Override public void save(Object obj) { System.out.println("save in db:" + obj); } }, FILE("file") { @Override public void save(Object obj) { System.out.println("save in file: " + obj); } }, OSS("oss") { @Override public void save(Object obj) { System.out.println("save in oss: " + obj); } }; private String type; SaveStrategyEnum(String type) { this.type = type; } public abstract void save(Object obj); public static SaveStrategyEnum typeOf(String type) { for (SaveStrategyEnum strategyEnum: values()) { if (strategyEnum.type.equalsIgnoreCase(type)) { return strategyEnum; } } return null; } } public void save(String type, Object data) { SaveStrategyEnum strategyEnum = SaveStrategyEnum.typeOf(type); if (strategyEnum != null) { strategyEnum.save(data); } } 复制代码
上面的实现,主要利用的是抽象类 + 枚举
来完成不同的策略具体实现
这种实现方式,相比较与前面的单例模式,还是更常见一点,虽然整体看下来没有什么难度,但是仔细看一看,会发现几个知识点
- 抽象方法的使用 (在模板设计模式中,更能体会抽象方法的使用妙处)
- 利用枚举原生提供的
values()
,来实现遍历,找到目标
3. 小结
枚举虽然说是 jdk 原生提供的一个基础数据类型,但是它的使用姿势除了我们熟知的常量之外,还可以有效的运用在设计模式中,让我们的代码实现更优雅
比如使用枚举来实现单例模式,就不用再面对让人烦躁的双重判断/内部类的方式了
使用枚举的策略模式,也可以有效解决我们类中大量的 if/else