策略模式就是定义一系列的算法,把它们一个个封装起来, 并且使它们可相互替换。
基本概念
策略模式主要是解决多种算法相似的情况下,使用if...else
所带来的复杂和难以维护。当存在系统中有多个类,但是区分它们的是只是它们的直接行为,那我们可以把这些封装成一个一个类,然后进行任意替换。
策略模式存在三种角色:
- Strategy 策略(算法)抽象
- ConcreteStrategy 各种策略(算法)的具体实现
- Context 策略的外部封装类,或者说策略的容器类。根据不同策略执行不同的行为。策略由外部环境决定。
案例
抽象类
public interface Strategy {public void encrypt();
}
定义算法抽象类,方法为加密。
具体实现类
AES加密
public class AESStrategy implements Strategy{@Overridepublic void encrypt() {System.out.println("执行AES");}}
MD5加密
public class MD5Strategy implements Strategy {@Overridepublic 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算法"){@Overridepublic Class<?> getStrategyClass() {return MD5Strategy.class;}},AES("AES算法"){@Overridepublic 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
的条件判断,算法可以自由切换。当遇到多个类似的算法策略,可以考虑策略模式。