Java设计模式——策略模式

概述

针对不同的应用场景采取不同的策略实现同一个方法,例如登陆的时候选择的不同登陆方式,目的都相同,可以用微信、QQ、用户名密码等等方法登陆。

将不同的内部算法封装成不同策略,调用者可以根据在调用的时候主动控制不同策略,实现同一功能。例如:登录这个功能,系统内部支持多种策略:手机验证码,用户名密码,微信号,QQ号登录等。

应用实例

定义一个动作画画(接口)

  1. public interface Draw {
  2. void drawPicture();
  3. }

用两个类去实现这个接口:画动物和画山水

  1. public class DrawAnimal implements Draw {
  2. @Override
  3. public void drawPicture() {
  4. System.out.println("画 飞禽走兽");
  5. }
  6. }
  1. public class DrawMountains implements Draw {
  2. @Override
  3. public void drawPicture() {
  4. System.out.println("画 山水");
  5. }
  6. }

创建一个枚举类,确定策略和实现类的映射关系

  1. public enum DrawStrategy {
  2. MOUNTAINS(new DrawMountains()),ANIMAL(new DrawAnimal());
  3. private Draw draw;
  4. public Draw getDraw() {
  5. return draw;
  6. }
  7. DrawStrategy(Draw draw) {
  8. this.draw = draw;
  9. }
  10. }

服务层

  1. public class DrawService {
  2. void drawThings(DrawStrategy strategy){
  3. strategy.getDraw().drawPicture();
  4. }
  5. }

测试

  1. /**
  2. * 以下是输出结果
  3. * 画 山水
  4. * 画 飞禽走兽
  5. */
  6. public class TestStrategy {
  7. public static void main(String[] args) {
  8. DrawService service=new DrawService();
  9. service.drawThings(MOUNTAINS);
  10. service.drawThings(ANIMAL);
  11. }
  12. }

总结

调用者可以根据自己的需求用不同算法实现功能

利用枚举的最大好处在于

  1. 语义清晰,不然会有很多内定的含义,比如,微信的时候你调用这个接口最后的参数传1,用户名密码的时候传2
  2. 当支持新增策略的时候,调用放能够很快的感知

策略模式还有一个特点,具体的实现逻辑是包含在枚举内部的,枚举类还有一定的分发功能,维护枚举对象到实现的映射关系

策略模式+委派模式

先上实例

定义一个新的枚举类型,与前者相比较,不再需要依赖具体的实现类了

  1. public enum DrawStrategyPlus {
  2. MOUNTAINS(1),ANIMAL(2);
  3. private int drawType;
  4. public int getDrawType() {
  5. return drawType;
  6. }
  7. DrawStrategyPlus(int drawType) {
  8. this.drawType = drawType;
  9. }
  10. }

接着定义策略模式和委派模式的核心服务类,它在静态方法中初始化一个Map,维护策略和实现类的关系,并且指定实现类去执行方法

  1. public class DrawStrategyDelegatePlus {
  2. private static Map<DrawStrategyPlus,Draw> drawStrategyMap=new HashMap<>();
  3. static {
  4. drawStrategyMap.put(DrawStrategyPlus.MOUNTAINS,new DrawMountains());
  5. drawStrategyMap.put(DrawStrategyPlus.ANIMAL,new DrawAnimal());
  6. }
  7. public void draw(DrawStrategyPlus strategyPlus){
  8. drawStrategyMap.get(strategyPlus).drawPicture();
  9. }
  10. }

测试

  1. /**
  2. * 以下是输出结果
  3. * 画 山水
  4. * 画 飞禽走兽
  5. */
  6. public class DrawStrategyDelegateTest {
  7. public static void main(String[] args) {
  8. DrawStrategyDelegatePlus drawStrategyDelegatePlus = new DrawStrategyDelegatePlus();
  9. drawStrategyDelegatePlus.draw(DrawStrategyPlus.MOUNTAINS);
  10. drawStrategyDelegatePlus.draw(DrawStrategyPlus.ANIMAL);
  11. }
  12. }

总结

策略模式+委派模式的实现将策略和委派业务分离,在委派的业务场景复杂,在经常需要扩展或者修改分发逻辑的的场景下更具有扩展性。

单纯的使用策略模式在新建枚举类型时调用者可以看到具体的实现类,但是第二种模式封装的更加彻底。

所以说策略模式其实包含了简单的分发逻辑,策略和委派更像是你中有我我中有你的感觉。设计模式之间不需要区分的特别明确,可以根据实际场景修改。