note

设计模式详解与实战指南

目录

  1. 策略模式
  2. 责任链模式
  3. 命令模式

策略模式

1.1 定义与目的

1.2 结构

客户端 ──┬── 策略接口(Strategy)
         │       ├── 具体策略A
         │       ├── 具体策略B
         │       └── 具体策略C
         │
         └── 策略上下文(Context)
                    └── 持有/选择策略

1.3 核心角色

1.4 代码结构

// 1. 策略接口
public interface Strategy {
    boolean supports(String context);
    String execute(ContextData data);
}

// 2. 具体策略
@Component
public class ConcreteStrategyA implements Strategy {
    @Override
    public boolean supports(String resource) {
        return "A".equals(resource);
    }
    @Override
    public String execute(ContextData data) {
        return "Result A";
    }
}

// 3. 策略注册器/上下文
@Component
public class StrategyRegistry {
    private final List<Strategy> strategies;
    public String handle(String resource, ContextData data) {
        return strategies.stream()
            .filter(s -> s.supports(resource))
            .findFirst()
            .orElseThrow(() -> new IllegalArgumentException("无可用策略"))
            .execute(data);
    }
}

1.5 适用场景

1.6 实际案例:日志格式化

传统写法(不推荐)

public String formatLog(String resource, String action, Object[] args) {
    switch (resource) {
        case "user":
            return String.format("用户操作: %s, 参数: %s", action, Arrays.toString(args));
        case "role":
            return String.format("角色操作: %s", action);
        case "permission":
            return String.format("权限操作: %s", action);
        default:
            return "未知操作";
    }
}

策略模式重构后

// Strategy 接口
public interface LogStrategy {
    boolean supports(String resource);
    String format(String action, Object[] args);
}

// 具体策略
@Component
public class UserLogStrategy implements LogStrategy {
    @Override
    public boolean supports(String resource) { return "user".equals(resource); }
    @Override
    public String format(String action, Object[] args) {
        return "用户" + getActionName(action) + ",参数:" + Arrays.toString(args);
    }
}

// 使用
@Service
public class LogService {
    private final List<LogStrategy> strategies;
    public String format(String resource, String action, Object[] args) {
        return strategies.stream()
            .filter(s -> s.supports(resource))
            .findFirst()
            .map(s -> s.format(action, args))
            .orElse("未知操作");
    }
}

1.7 注意事项


责任链模式

2.1 定义与目的

2.2 结构

客户端 ──┬── 处理器1 ── 处理器2 ── 处理器3 ── ... ── 末端处理器
         │          │          │
         └──────────┴──────────┴── (链式调用)

2.3 核心角色

2.4 代码结构

版本1:显式链(固定顺序)

// 处理器接口
public interface Handler {
    void handle(Request request);
    void setNext(Handler next);
}

// 具体处理器
public class HandlerA implements Handler {
    private Handler next;
    @Override
    public void handle(Request request) {
        if (shouldHandle(request)) {
            process(request);
        } else if (next != null) {
            next.handle(request);
        }
    }
}

// 客户端组装链
Handler chain = new HandlerA();
chain.setNext(new HandlerB());
chain.setNext(new HandlerC());
chain.handle(request);

版本2:隐式链(自动扫描 + 顺序控制)

// 处理器接口(简化版)
public interface Validator {
    int order();
    void validate(Request request);
}

// 链管理器
@Component
public class ValidatorChain {
    private final List<Validator> validators;
    public void validate(Request request) {
        validators.stream()
            .sorted(Comparator.comparingInt(Validator::order))
            .forEach(v -> v.validate(request));
    }
}

2.5 适用场景

2.6 实际案例:用户注册校验

需求:新用户注册需依次校验

  1. 用户名格式(3-20 位字母/数字/下划线)
  2. 用户名唯一性
  3. 密码强度(含大小写字母+数字,≥8 位)
  4. 邮箱格式

传统写法(不推荐)

public void register(UserDTO dto) {
    if (!dto.getUsername().matches("^[a-zA-Z0-9_]{3,20}$")) {
        throw new BizException("用户名格式错误");
    }
    if (userService.exists(dto.getUsername())) {
        throw new BizException("用户名已存在");
    }
    if (!isStrong(dto.getPassword())) {
        throw new BizException("密码强度不足");
    }
    if (!EmailValidator.getInstance().isValid(dto.getEmail())) {
        throw new BizException("邮箱格式错误");
    }
    // 业务逻辑...
}

责任链模式重构后

// 1. 校验器接口
public interface UserRegisterValidator {
    int order();
    void validate(UserDTO dto) throws ValidationException;
}

// 2. 实现类
@Component
public class UsernameFormatValidator implements UserRegisterValidator {
    @Override public int order() { return 1; }
    @Override
    public void validate(UserDTO dto) {
        if (!dto.getUsername().matches("^[a-zA-Z0-9_]{3,20}$")) {
            throw new ValidationException("用户名格式错误");
        }
    }
}

@Component
public class UsernameUniqueValidator implements UserRegisterValidator {
    @Override public int order() { return 2; }
    @Override
    public void validate(UserDTO dto) {
        if (userService.exists(dto.getUsername())) {
            throw new ValidationException("用户名已存在");
        }
    }
}

// 3. 链管理器(自动组装)
@Component
public class ValidatorChain {
    private final List<UserRegisterValidator> validators;
    public void validate(UserDTO dto) {
        validators.stream()
            .sorted(Comparator.comparingInt(UserRegisterValidator::order))
            .forEach(v -> v.validate(dto));
    }
}

// 4. 使用
@Service
public class UserService {
    private final ValidatorChain validatorChain;
    public void register(UserDTO dto) {
        validatorChain.validate(dto);  // 自动按顺序执行
        // 业务逻辑...
    }
}

2.7 注意事项


命令模式

3.1 定义与目的

3.2 结构

调用者 (Invoker) ──┬── Command(命令接口)
                   │         ├── ConcreteCommandA
                   │         └── ConcreteCommandB
                   │
                   └──► 接收者 (Receiver)
                          ├── 方法A()
                          └── 方法B()

3.3 核心角色

3.4 代码结构

简单版本(内存栈)

// 1. 命令接口
public interface Command {
    void execute();
    void undo();
}

// 2. 具体命令
public class GrantPermissionsCommand implements Command {
    private final RoleService roleService;
    private final Long roleId;
    private final List<Long> permissionIds;
    public GrantPermissionsCommand(RoleService roleService, Long roleId, List<Long> permissionIds) {
        this.roleService = roleService;
        this.roleId = roleId;
        this.permissionIds = permissionIds;
    }
    @Override
    public void execute() {
        roleService.grant(roleId, permissionIds);
    }
    @Override
    public void undo() {
        roleService.revoke(roleId, permissionIds);
    }
}

// 3. 调用器(维护历史栈)
@Component
public class CommandInvoker {
    private final Deque<Command> history = new ArrayDeque<>();
    public void execute(Command command) {
        command.execute();
        history.push(command);
    }
    public void undo() {
        if (history.isEmpty()) throw new IllegalStateException("无历史记录");
        Command command = history.pop();
        command.undo();
    }
}

持久化版本(数据库记录)

// 命令历史实体(用于持久化)
@Entity
public class CommandHistory {
    private Long id;
    private String type;           // "grant" / "revoke"
    private String payload;        // JSON 序列化的参数
    private String status;         // "done" / "undone"
}

// Invoker(存储到数据库)
@Component
public class CommandInvoker {
    private final CommandHistoryRepository historyRepo;
    public void execute(Command command, String type, List<Long> args) {
        command.execute();
        historyRepo.save(new CommandHistory(type, toJson(args), "done"));
    }
    public void undo() {
        CommandHistory last = historyRepo.findTopByStatusOrderByIdDesc("done");
        Command command = rebuild(record);  // 反序列化重建命令
        command.undo();
        record.setStatus("undone");
        historyRepo.save(record);
    }
}

3.5 适用场景

3.6 实际案例:角色权限编辑

需求

传统写法(问题)

public void grantPermissions(Long roleId, List<Long> permissionIds) {
    Role role = roleRepository.findById(roleId);
    rolePermissionRepository.deleteByRoleId(roleId);
    rolePermissionRepository.batchInsert(roleId, permissionIds);
}
//撤销?不知道之前是什么状态,无法回退

命令模式解决方案

// 1. 命令接口
public interface RolePermissionCommand {
    void execute();
    void undo();
}

// 2. 授权命令
public class GrantCommand implements RolePermissionCommand {
    private final RolePermissionService service;
    private final Long roleId;
    private final List<Long> permissionIds;
    @Override
    public void execute() {
        service.insert(roleId, permissionIds);
    }
    @Override
    public void undo() {
        service.delete(roleId, permissionIds);
    }
}

// 3. 撤权命令
public class RevokeCommand implements RolePermissionCommand {
    private final RolePermissionService service;
    private final Long roleId;
    private final List<Long> permissionIds;
    @Override
    public void execute() {
        service.delete(roleId, permissionIds);
    }
    @Override
    public void undo() {
        service.insert(roleId, permissionIds);
    }
}

// 4. 调用器(持久化版)
@Component
public class RolePermissionInvoker {
    private final CommandHistoryRepository historyRepo;
    private final RolePermissionService service;
    public void grant(Long roleId, List<Long> permissionIds) {
        GrantCommand cmd = new GrantCommand(service, roleId, permissionIds);
        executeAndRecord(cmd, roleId, "grant", permissionIds);
    }
    public void undo(Long roleId) {
        CommandHistory last = historyRepo.findTopByRoleIdAndStatusOrderByIdDesc(
            roleId, "done");
        if (last == null) throw new IllegalStateException("无历史记录");
        RolePermissionCommand cmd = rebuildFromHistory(last);
        cmd.undo();
        last.setStatus("undone");
        historyRepo.save(last);
    }
    private void executeAndRecord(RolePermissionCommand cmd, Long roleId,
                                   String type, List<Long> permissionIds) {
        cmd.execute();
        historyRepo.save(new CommandHistory(roleId, type,
            toJson(permissionIds), "done"));
    }
}

3.7 注意事项


对比总结

维度 策略模式 责任链模式 命令模式
核心思想 封装算法,可互换 请求沿链传递,直到被处理 请求封装为对象
耦合关系 客户端 → 策略接口 客户端 → 链头(不感知后续) 调用者 → 命令 → 接收者
对象间的联系 策略之间相互独立 有明确的父子链 命令持有接收者引用
典型场景 多种算法切换 多层审批、过滤器链 撤销重做、事务补偿
参数传递 上下文对象 沿链向下传递 构造函数注入命令对象