通过清除“if”语句来保持代码整洁

2025-05-28

通过清除“if”语句来保持代码整洁

努力实现更简洁的代码

我认为,最常见的导致代码难以阅读的原因是过度使用“if”语句。它是我们学习的第一批编程工具之一,通常当我们了解到计算机几乎可以做任何我们想做的事情时,前提是“if”我们正确地使用了这些语句。接下来通常是漫长的printf和调试过程,试图弄清楚为什么程序没有进入我们确信它会进入的第三个嵌套“if”!我们中的许多人就是这样接触编程的,并且已经习惯了。

随着我对代码设计和最佳实践的研究越来越深入,我开始注意到大量使用 if 语句可能是一种反模式,会使代码的阅读、调试和维护变得更糟。因此,我开始寻找这些 if 语句的替代模式,我认为这些模式提高了我的代码的可读性和可维护性。

当然,没有万能的灵丹妙药,任何模式都应该在合理的地方使用。我认为,对于我们开发人员来说,在尝试编写高质量代码时,拥有选择权非常重要。

为了说明这一点,我将分享两个简单的例子,并希望在评论中听到您对此事的看法。

首先,让我们看一个例子,我们需要处理来自应用程序边界之外的传入消息,并且该对象包含一个指定类型的字符串属性。它可能是来自群发邮件营销的错误类型,我们必须将其转换为我们自己域的错误类型。

通常我看到的实现方式如下:



    private ErrorType translateErrorType(String errorString) {
        if ("Undetermined".equals(errorString)) {
            return UNKNOWN_ERROR;
        } else if ("NoEmail".equals(errorString)) {
            return INVALID_RECIPIENT;
        } else if ("MessageTooLarge".equals(errorString)) {
            return INVALID_CONTENT;
        } else if ("ContentRejected".equals(errorString)) {
            return INVALID_CONTENT;
        } else if ("AttachmentRejected".equals(errorString)) {
            return INVALID_CONTENT;
//      } else if (...)

        } else {
            throw new IllegalArgumentException("Error type not supported: " + errorTypeString);
        }
    }


Enter fullscreen mode Exit fullscreen mode

你知道这是怎么回事吧?它可能是一个 switch 语句,而且同样会很混乱,包含的语言特定词汇比实际业务领域语言多得多。

有很多方法可以摆脱这种“如果”的纠缠,但我想最简单的方法就是使用地图。



    public class ErrorTypeTranslator {

        private final static Map<String, ErrorType> errorTypeMap;

        static {
            errorTypeMap = Map.of(
            "Undetermined", UNKNOWN_ERROR,
            "NoEmail", INVALID_RECIPIENT,
            "MessageTooLarge", INVALID_CONTENT,
            "ContentRejected", INVALID_CONTENT,
            "AttachmentRejected", INVALID_CONTENT
//          (…)
            );
        }

        public ErrorType translateErrorType(String errorTypeString) {
            return requireNonNull(errorTypeMap.get(errorTypeString),
                    () -> "Error type not supported: " + errorTypeString 
        }
    }


Enter fullscreen mode Exit fullscreen mode

发现区别了吗?现在,业务逻辑占据了中心位置,任何接触这个类的开发人员都应该能够轻松理解它的功能,并在需要时进行修改。许多语言特有的词汇和符号消失了,取而代之的是更加美观、简洁且不易出错的代码。

这种模式对于简单的工厂模式也非常适用,你可以使用单例或供应商的 Map 作为值。例如,假设你需要根据从数据库检索到的枚举返回一个处理程序 bean。

我通常看到的是这样的:



    public class IntegrationHandlerFactory {

        private final EmailIntegrationHandler emailHandler;
        private final SMSIntegrationHandler smsHandler;
        private final PushIntegrationHandler pushHandler;

        public IntegrationHandlerFactory(EmailIntegrationHandler emailHandler,
                              SMSIntegrationHandler smsHandler,
                              PushIntegrationHandler pushHandler) {
            this.emailHandler = emailHandler;
            this.smsHandler = smsHandler;
            this.pushHandler = pushHandler;
        }

        public IntegrationHandler getHandlerFor(Integration integration) {
            if (EMAIL.equals(integration)) {
                return emailHandler;
            } else if (SMS.equals(integration)) {
                return smsHandler
            } else if (PUSH.equals(integration)) {
                return pushHandler
            } else {
                throw new IllegalArgumentException("No handler found for integration: " + integration);
            }

        }
    }


Enter fullscreen mode Exit fullscreen mode

让我们尝试使用 Map 来代替:



    public class IntegrationHandlerFactory {

        private final Map<Integration, IntegrationHandler> handlerMap;

        public IntegrationHandlerFactory(EmailIntegrationHandler emailHandler,
                              SMSIntegrationHandler smsHandler,
                              PushIntegrationHandler pushHandler) {

            handlerMap = Map.of(
                        EMAIL, emailHandler,
                        SMS, smsHandler,
                        PUSH, pushHandler
            );
        }

        public IntegrationHandler getHandlerFor(Integration integration) {
            return requireNonNull(handlerMap.get(integration),
                            () -> "No handler found for integration: " + integration);
        }

    }


Enter fullscreen mode Exit fullscreen mode

是不是简洁多了?又是一个简洁的设计,省去了一堆 if / else if 语句,而且添加新选项也变得非常容易。

还有很多其他类似的模式,我可能很快会发布一篇有关它们的文章。

那么,你对这类模式有什么看法?你用过这样的模式吗?你更习惯用“if”语句吗?

请在评论中告诉我,我很乐意听到您的反馈!

我发表了一篇关于另一种有助于避免重复 if 的模式的帖子,想看看吗?

文章来源:https://dev.to/tomazlemos/keeping-your-code-clean-by-sweeping-out-if-statements-4in8
PREV
JavaScript 中的模块模式
NEXT
我说过,React 不需要状态管理工具