策略模式就是定义一系列的算法,把它们一个个封装起来, 并且使它们可相互替换。
基本概念
策略模式主要是解决多种算法相似的情况下,使用if...else
所带来的复杂和难以维护。当存在系统中有多个类,但是区分它们的是只是它们的直接行为,那我们可以把这些封装成一个一个类,然后进行任意替换。
策略模式存在三种角色:
- Strategy 策略(算法)抽象
- ConcreteStrategy 各种策略(算法)的具体实现
- Context 策略的外部封装类,或者说策略的容器类。根据不同策略执行不同的行为。策略由外部环境决定。
案例
抽象类
public interface Strategy {
public void encrypt();
}
定义算法抽象类,方法为加密。
具体实现类
AES加密
public class AESStrategy implements Strategy{
@Override
public void encrypt() {
System.out.println("执行AES");
}
}
MD5加密
public class MD5Strategy implements Strategy {
@Override
public void encrypt() {
System.out.println("执行MD5");
}
}
继承算法抽象类,具体用AES、MD5方法进行实现。
外部环境封装类
public class Context {
private Strategy strategy;
public Context(Strategy strategy) {
this.strategy=strategy;
}
public void encrypt(){
this.strategy.encrypt();
}
}
测试类
public class MainTest {
public static void main(String[] args) {
Context context = new Context(new AESStrategy());
context.encrypt();
}
}
小改一下
上面测试使用的时候,需要自己新建一个实例,阅读性不够好,所以就重新用枚举类修改一下。
算法枚举类
public enum StrategyEnums {
MD5("MD5算法"){
@Override
public Class<?> getStrategyClass() {
return MD5Strategy.class;
}
},AES("AES算法"){
@Override
public Class<?> getStrategyClass() {
return AESStrategy.class;
}
};
public abstract Class<?> getStrategyClass();
private String className;
StrategyEnums(){}
StrategyEnums(String className){
this.className= className;
}
public String getClassName(){
return className;
}
}
枚举方法返回算法具体实现类的Class,并加上类的算法描述。
public class Context {
private Strategy strategy;
public Context(StrategyEnums enums) {
try {
this.strategy = (Strategy) enums.getStrategyClass().newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
public void encrypt(){
this.strategy.encrypt();
}
}
包装类的参数改为枚举值,根据枚举值来构建实例。
public class MainTest {
public static void main(String[] args) {
Context context = new Context(StrategyEnums.AES);
context.encrypt();
}
}
测试可用,但是这样的话,就是需要同时维护枚举类,新构建一个算法具体类,同时要维护枚举类,不过就是增加了可读性。
总结
使用策略方式可以提供良好的扩展性、避免大量的if...else
的条件判断,算法可以自由切换。当遇到多个类似的算法策略,可以考虑策略模式。