命令模式 -- 实践

2021-02-02  本文已影响0人  东南枝下

学习命令模式后,使用命令模式对项目中switch做一些优化
在重构一书Switch Statements(switch惊悚现身)这一节中也阐述了重构switch的理由
使用命令模式来重构,本质上是使用多态来取代switch

原代码如下:

    switch (fieldType) {
            case enum1:
                doSomething(parameter);
                break;
            case enum2:
                     ...
                break;
                     ...
            default:
                break;
        }

原本的代码根据fieldType值的不同执行不同的逻辑,而这个fieldType来源于一个注解的参数

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD})
public @interface Annotation {
    /**
     * 根据不同的类别选择不同的处理方式
     *
     * @return 类别枚举
     */
    FieldType fieldType();
    ...
}

FieldType 则是一个枚举类

public enum FieldType {
  ...
}

重构方式如下:

  1. 接收者:这里将具体的业务逻辑执行类看作接收者,原本的代码已经可以复用,不做特别的关注

  2. 命令角色

/**
 * 命令抽象接口
 *
 * @author Jenson
 */
public interface Command {

    /**
     * 设置参数
     *
     * @param parameter 参数
     */
    void setParameter(Parameter parameter);

    /**
     * 执行命令
     */
    void execute();
}
  1. 具体的命令
/**
 * @author Jenson
 */
@Component
public class DoSomethingCommand implements Command {

    private Parameter parameter;

    @Override
    public void setParameter(Parameter parameter) {
        this.parameter = parameter;
    }

    @Override
    public void execute() {
        doSomething(parameter);
    }
}

具体的命令实现命令接口,在这里完成原本应该在case中完成的工作,每一个case对应一个具体的命令实现。这样即使以后需要增加别的情况,也只需要增加命令实现类就好了,无需再去动、去阅读研究以前的代码。撒花~

  1. 调用者
    这里做的比较简单就是个没得感情的调用机器
/**
 * 调用者抽象角色
 *
 * @author Jenson
 */
public interface Invoker {
    /**
     * 执行命令
     *
     * @param command 命令
     */
    void action(Command command);
}

/**
 * @author Jenson
 */
@Component
public class InvokerImpl implements Invoker {

    @Override
    public void action(Command command) {
        command.execute();
    }
}
  1. 重构原代码
        Invoker invoker = SpringContextUtil.getBean(InvokerImpl.class);
        Command command = (Command) SpringContextUtil.getBean(concreteCommand);
        command.setParameter(currentTenantId, fieldValueList, valueMap);
        invoker.action(command);
// --------------原代码对比如下----------------
//      switch (fieldType) {
//          case enum1:
//              doSomething(parameter);
//              break;
//          case enum2:
//                     ...
//              break;
//                     ...
//          default:
//              break;
//      }

上述代码将fieldType替换为concreteCommand,concreteCommand是具体的命令实现类,
此处修改了注解的传入参数

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD})
public @interface Annotation {
    /**
     * 选择不同的命令来处理
     *
     * @return 命令类
     */
    Class concreteCommand();

// --------------原代码对比如下----------------
//      /**
//       * 根据不同的类别选择不同的处理方式
//       *
//       * @return 类别枚举
//       */
//      FieldType fieldType();
//      ...
}

类图如下:

图片.png

后记:虽说是命令模式,但从使用的结果来看,却是策略模式

上一篇下一篇

猜你喜欢

热点阅读