背景
- Enum是否支持序列化,以及底层的实现原理
- Enum类型的策略枚举这种设计模式如何实现和优缺点
Enum支持序列化吗
支持,在Java中,只要一个类实现了java.io.Serializable接口,那么它就可以被序列化。
Enum底层实现
当我们使用enmu来定义一个枚举类型的时候,编译器会自动帮我们创建一个final类型的类继承Enum类,所以枚举类型不能被继承,这个类中有几个属性和方法都是static类型的,因为static类型的属性会在类被加载之后被初始化,当一个Java类第一次被真正使用到的时候静态资源被初始化、Java类的加载和初始化过程都是线程安全的。所以,创建一个enum类型是线程安全的。
一旦实现了Serializable接口之后,就不再是单例得了,因为,每次调用 readObject()方法返回的都是一个新创建出来的对象,有一种解决办法就是使用readResolve()方法来避免此事发生。但是,为了保证枚举类型像Java规范中所说的那样,每一个枚举类型极其定义的枚举变量在JVM中都是唯一的,在枚举类型的序列化和反序列化上,Java做了特殊的规定。
在序列化的时候Java仅仅是将枚举对象的name属性输出到结果中,反序列化的时候则是通过java.lang.Enum的valueOf方法来根据名字查找枚举对象。同时,编译器是不允许任何对这种序列化机制的定制的,因此禁用了writeObject、readObject、readObjectNoData、writeReplace和readResolve等方法。原文参考深度分析 Java 的枚举类型
设计模式之策略枚举
策略模式定义
定义一系列的算法,把每一个算法封装起来, 并且使它们可相互替换。本模式使得算法可独立于使用它的客户而变化。也称为政策模式(Policy)。(Definea family of algorithms,encapsulate each one, andmake them interchangeable. Strategy lets the algorithmvary independently from clients that use it. )
从以上官方定义分析到策略模式具有三个角色分别是:
- 环境类(Context):(如上图中的Context,根据不同的使用环境调用不同的策略接口)
- 抽象策略类(Strategy):(策略接口,如上图中的Strategy)
- 具体策略类(ConcreteStrategy):(实现策略接口的类:如上图中的ConcreteStrategyA,B,C)
策略举例
以加减法为例来划分一下其中的角色,比如 加法:1+1=2,减法1-1=0。
可以抽象出来为除了加减的符号不同其他都是一样的:两个参数,一操作符号,和返回值。
因此可以定义个接口
参考源码作者: 策略模式(政策模式) 策略枚举
/**
* 定义策略接口(一组策略)
* @author yanwenfei
*
*/
public interface IStrategy {
//策略需要执行的方法
public int exec(int a, int b);
}
接下来实现加减的两个具体算法
/**
* 策略A加法
* @author yanwenfei
*
*/
public class StrategyADD implements IStrategy {
@Override
public int exec(int a, int b) {
return a+b;
}
}
/**
* 减法策略
* @author yanwenfei
*
*/
public class StrategySub implements IStrategy {
@Override
public int exec(int a, int b) {
return a - b;
}
}
策略封装,而高层不用知道具体是哪种策略,只需要调用抽象策略的方法即可
/**
* 策略环境即封装
* @author yanwenfei
*/
public class Calculator {
private IStrategy strategy;
//切换策略
public Calculator(IStrategy strategy) {
this.strategy = strategy;
}
//执行策略方法
public int exec(int a, int b){
return strategy.exec(a, b);
}
}
策略调用
public class TestMain {
public static void main(String[] args) {
Calculator calculator = null;
IStrategy streadd = new StrategyADD();//创建加法策略;
calculator = new Calculator(streadd);//切换策略
int add = calculator.exec(20, 30);
System.out.println("20 + 30 = " + add);
IStrategy stresub = new StrategySub();//创建减法策略;
calculator = new Calculator(stresub);//切换策略
int sub = calculator.exec(20, 30);
System.out.println("20 - 30 = " + sub);
}
}
以上为策略模式传统的实现方式,肯定很多人能看出来这个策略模式有很多缺点,虽然便于扩展,但是每一个策略都是一个类,这个先不说,下来看一下更简略的策略枚举。
策略枚举
/**
* 策略枚举
* @author yanwenfei
*/
public enum Calculator {
ADD("+") {
@Override
public int exec(int a, int b) {
// TODO Auto-generated method stub
return a+b;
}
},
SUB("-") {
@Override
public int exec(int a, int b) {
// TODO Auto-generated method stub
return a-b;
}
};
public abstract int exec(int a, int b);
//运算符
private String value = "";
private Calculator(String value) {
this.value = value;
}
public String getValue() {
return value;
}
}
调用策略
public class TestMain {
public static void main(String[] args) {
int add = Calculator.ADD.exec(10, 30);
System.out.println("10 + 30 = "+add);
int sub = Calculator.SUB.exec(10, 30);
System.out.println("10 - 30 = "+sub);
}
}
策略模式优缺点
策略模式优点
- 算法可以自由切换(高层屏蔽算法,角色自由切换)
- 避免使用多重条件判断(如果算法过多就会出现很多种相同的判断,很难维护)
- 扩展性好(可自由添加取消算法 而不影响整个功能)
策略模式缺点
- 策略类数量增多(每一个策略类复用性很小,如果需要增加算法,就只能新增类)
- 所有的策略类都需要对外暴露(使用的人必须了解使用策略,这个就需要其它模式来补充,比如工厂模式、代理模式)