如何通过命令模式与访问者模式消除错误类型判断的 if-else 耦合

陌丽小哥_6198

陌丽小哥_6198

2026-05-22

205人浏览

原创

如何通过命令模式与访问者模式消除错误类型判断的 if-else 耦合

本文介绍如何使用命令模式统一事件处理流程,并结合访问者模式或策略式错误处理器,彻底消除 instanceof 类型判断的 if-else 耦合,提升面向对象设计的可扩展性与可维护性。

本文介绍如何使用命令模式统一事件处理流程,并结合访问者模式或策略式错误处理器,彻底消除 `instanceof` 类型判断的 if-else 耦合,提升面向对象设计的可扩展性与可维护性。

在原始代码中,EventProcessor 类通过硬编码的 if (result instanceof XxxError) 分支分别处理不同错误类型,导致逻辑分散、重复且难以扩展——每当新增错误子类或事件类型,就必须修改多处 onEventX() 方法。这种设计违反了开闭原则(OCP)和单一职责原则(SRP)。根本解法在于将“行为”与“决策”解耦:用命令模式封装执行逻辑,用错误处理器(基于访问者或策略模式)统一响应错误。

✅ 推荐重构方案:命令 + 错误策略处理器

我们不采用原文中 Command#getError() 硬编码错误生成的方式(这违背了命令职责),而是聚焦核心目标:消除 instanceof 分支。以下是生产就绪的重构步骤:

1. 定义统一事件接口与错误处理器

// 统一事件契约(Event1/Event2 实现此接口)
public interface Event {
    void setStatus(EventStatus status);
}

// 错误处理器:为每种错误定义专属处理逻辑
public interface ErrorHandler {
    void handle(NoProcessorFoundError error, Event event);
    void handle(UnknownError error, Event event);
    // 新增错误类型时,仅需在此接口添加新方法(符合OCP)
}

2. 使用访问者模式消除 instanceof(推荐)

// 错误基类支持访问者
public abstract class Error {
    public abstract <t> T accept(ErrorVisitor<t> visitor);
}

public interface ErrorVisitor<t> {
    T visit(NoProcessorFoundError error);
    T visit(UnknownError error);
}

// 具体错误实现
public class NoProcessorFoundError extends Error {
    @Override
    public <t> T accept(ErrorVisitor<t> visitor) {
        return visitor.visit(this);
    }
}

public class UnknownError extends Error {
    @Override
    public <t> T accept(ErrorVisitor<t> visitor) {
        return visitor.visit(this);
    }
}</t></t></t></t></t></t></t>

3. 命令类封装事件处理与状态更新

public abstract class EventCommand<t extends event> {
    protected final T event;

    public EventCommand(T event) {
        this.event = event;
    }

    // 模板方法:执行处理 → 解析结果 → 委托给错误处理器
    public final void execute() {
        Error result = doProcess();
        if (result != null) {
            new ErrorStatusHandler().handle(result, event);
        }
    }

    protected abstract Error doProcess();

    // 内部错误处理器:集中定义状态映射规则
    private static class ErrorStatusHandler implements ErrorHandler {
        @Override
        public void handle(NoProcessorFoundError error, Event event) {
            event.setStatus(EventStatus.RETRYABLE); // 或 REJECTED,按事件类型动态决定
        }

        @Override
        public void handle(UnknownError error, Event event) {
            event.setStatus(EventStatus.FAILED);
        }
    }
}

// 具体命令实现(无重复 if-else)
public class ProcessEvent1Command extends EventCommand<event1> {
    public ProcessEvent1Command(Event1 event) {
        super(event);
    }

    @Override
    protected Error doProcess() {
        return Event1Processors.process(event); // 返回具体错误实例
    }
}

public class ProcessEvent2Command extends EventCommand<event2> {
    public ProcessEvent2Command(Event2 event) {
        super(event);
    }

    @Override
    protected Error doProcess() {
        return Event2Processors.process(event);
    }
}</event2></event1></t>

4. 使用示例(简洁、可测试、易扩展)

// 事件处理入口
public class EventProcessor {
    public void onEvent1(Event1 event) {
        new ProcessEvent1Command(event).execute();
    }

    public void onEvent2(Event2 event) {
        new ProcessEvent2Command(event).execute();
    }
}

// 单元测试友好:可直接 new Command(...).execute()
@Test
void testNoProcessorFoundError_setsRetryable() {
    Event1 event = new Event1();
    new ProcessEvent1Command(event) {
        @Override
        protected Error doProcess() {
            return new NoProcessorFoundError(); // 模拟返回
        }
    }.execute();
    assertEquals(EventStatus.RETRYABLE, event.getStatus());
}

⚠️ 注意事项与最佳实践

  • 避免过度设计:若错误类型极少且稳定,可直接用 Map, BiConsumer> 策略注册表替代访问者,更轻量;
  • 状态映射应解耦:RETRYABLE/REJECTED 等状态不应硬编码在处理器中,建议通过 EventContext 或配置中心注入;
  • 异常 vs 错误对象:考虑将 Error 改为 Result(如 Result.success(data) / Result.failure(error)),更符合函数式风格;
  • 命令组合:后续可扩展 CompositeCommand 支持事务性多事件处理。

通过该重构,instanceof 分支彻底消失,新增错误类型只需:

  1. 继承 Error 并实现 accept();
  2. 在 ErrorHandler 中添加对应 handle() 方法;
  3. 在 ErrorStatusHandler 中补充处理逻辑。
    零侵入现有命令类,真正实现高内聚、低耦合的 OO 设计。
PHP速学视频免费教程(入门到精通)
PHP速学视频免费教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
java
java

Java是一个通用术语,用于表示Java软件及其组件,包括“Java运行时环境 (JRE)”、“Java虚拟机 (JVM)”以及“插件”。php中文网还为大家带了Java相关下载资源、相关课程以及相关文章等内容,供大家免费下载使用。

2023.06.15

10537

6

java正则表达式语法
java正则表达式语法

java正则表达式语法是一种模式匹配工具,它非常有用,可以在处理文本和字符串时快速地查找、替换、验证和提取特定的模式和数据。本专题提供java正则表达式语法的相关文章、下载和专题,供大家免费下载体验。

2023.07.05

7662

9

java自学难吗
java自学难吗

Java自学并不难。Java语言相对于其他一些编程语言而言,有着较为简洁和易读的语法,本专题为大家提供java自学难吗相关的文章,大家可以免费体验。

2023.07.31

6672

8

java配置jdk环境变量
java配置jdk环境变量

Java是一种广泛使用的高级编程语言,用于开发各种类型的应用程序。为了能够在计算机上正确运行和编译Java代码,需要正确配置Java Development Kit(JDK)环境变量。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

2023.08.01

1144

3

java保留两位小数
java保留两位小数

Java是一种广泛应用于编程领域的高级编程语言。在Java中,保留两位小数是指在进行数值计算或输出时,限制小数部分只有两位有效数字,并将多余的位数进行四舍五入或截取。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

2023.08.02

928

3

java基本数据类型
java基本数据类型

java基本数据类型有:1、byte;2、short;3、int;4、long;5、float;6、double;7、char;8、boolean。本专题为大家提供java基本数据类型的相关的文章、下载、课程内容,供大家免费下载体验。

2023.08.02

1376

5

java有什么用
java有什么用

java可以开发应用程序、移动应用、Web应用、企业级应用、嵌入式系统等方面。本专题为大家提供java有什么用的相关的文章、下载、课程内容,供大家免费下载体验。

2023.08.02

2769

5

java在线网站
java在线网站

Java在线网站是指提供Java编程学习、实践和交流平台的网络服务。近年来,随着Java语言在软件开发领域的广泛应用,越来越多的人对Java编程感兴趣,并希望能够通过在线网站来学习和提高自己的Java编程技能。php中文网给大家带来了相关的视频、教程以及文章,欢迎大家前来学习阅读和下载。

2023.08.03

20071

3

配置java环境变量
配置java环境变量

配置Java环境变量是为了让操作系统能够识别和使用Java的相关命令和功能。本专题为大家提供配置java环境变量相关文章,帮助大家解决问题。

2023.08.03

1235

8

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
热门推荐
/
最新课程
phpStudy极速入门视频教程
phpStudy极速入门视频教程

共6课时 | 54.7万人学习

独孤九贱(4)_PHP视频教程
独孤九贱(4)_PHP视频教程

共89课时 | 133.7万人学习