重构手法——函数行为重塑类 | 语意 | 用命令替换函数

43 阅读2分钟

简介

"用命令替换函数"是一种面向对象的重构手法。通过将复杂函数封装为独立命令对象,可以解耦操作与参数,支持事务操作、撤销机制等复杂需求,提升代码的可扩展性。

针对的症状(代码坏味道)

  • 包含多个参数的长方法
  • 需要支持撤销/重做操作
  • 方法状态依赖外部上下文
  • 需要将操作作为参数传递

用命令替换函数的详细步骤

  1. 创建命令基类
    • 定义执行操作的抽象方法
    • 封装公共参数和状态
  2. 实现具体命令
    • 将原函数逻辑迁移到命令类
    • 实现参数传递机制
  3. 重构调用方
    • 用命令对象替换函数调用
    • 维护命令生命周期
  4. 支持高级特性
    • 添加undo/redo方法
    • 实现命令队列支持

示例

重构前代码:

class Calculator {
    double calculate(double a, double b, String operator) {
        switch (operator) {
            case "+":
                return a + b;
            case "-":
                return a - b;
            case "*":
                return a * b;
            case "/":
                return a / b;
            default:
                throw new IllegalArgumentException();
        }
    }
}

重构步骤:

  1. 定义命令接口:

    interface MathCommand {
        double execute(double a, double b);
    }
    
  2. 实现具体命令类:

    class AddCommand implements MathCommand {
        public double execute(double a, double b) {
            return a + b;
        }
    }
    
    // 类似实现SubtractCommand、MultiplyCommand、DivideCommand
    
  3. 重构计算器类:

    class Calculator {
        double calculate(double a, double b, MathCommand command) {
            return command.execute(a, b);
        }
    }
    

练习

基础练习题

  1. 简单操作命令化

    // 重构前
    class FileManager {
        void compressFile(String path) {
            // 压缩文件逻辑
        }
    }
    

进阶练习题

  1. 带状态命令改造

    // 重构前
    class Editor {
        void applyFont(Text text, Font font, boolean underline) {
            text.setFont(font);
            if (underline) text.setUnderline(true);
        }
    }
    

综合拓展练习题

  1. 支持撤销的命令系统

    // 重构前
    class DiagramEditor {
        void moveShape(Shape shape, int dx, int dy) {
            shape.setX(shape.getX() + dx);
            shape.setY(shape.getY() + dy);
        }
    }
    

代码审查要点

  1. 优点:

    • 提高代码的可测试性
    • 支持复杂操作组合
    • 分离操作定义与执行
  2. 潜在问题:

    • 避免过度设计简单操作
    • 注意命令对象的生命周期管理
    • 合理设计命令接口参数