我编写简单代码的 4 个最佳模式

2025-06-08

我编写简单代码的 4 个最佳模式

说到写代码,我的目标是写出简洁的代码。也就是 Bob Martin 所说的“干净的代码”。其他人称之为“可读的”或“可维护的”。从很多方面来说,它们都指的是同一件事。

但这很难

编写简单的代码需要深思熟虑。它需要几轮重构,直到代码完美为止。这通常需要同行评审或结对编程。

但我在职业生涯中发现了一些模式,它们帮助我编写了简单的代码。不一定更快或更容易,但更简洁。当我遇到新问题时,我就会求助于这些模式,它们几乎总能把复杂的事情变得简单一些。

关于模式

简单介绍一下,当我提到模式时,通常指的是你可能听说过的一组OOP 模式。我知道 OOP 在很多方面已经过时了——但无论你偏爱哪种范式,其中一些模式仍然适用。它们都倾向于简单的组合而不是继承,而继承正是大多数人讨厌 OOP 的地方。

我这里提到的大部分模式都出自四人组的经典著作《设计模式》。我只会对每个模式做一个简短的介绍,因此强烈建议你点击提供的链接来更详细地了解它们。

模式 1:抽象工厂

工厂本质上是一个对象,它的唯一任务就是生成其他对象。工厂可以以不同的方式实现,但我认为抽象工厂模式是最强大的。

抽象工厂不仅允许您在运行时更改已生成或构建的对象,还可以潜在地在运行时更改工厂本身。虽然这听起来有点奇怪,但它对于 Spring 或 Unity 等控制反转框架来说确实非常有效。

从代码角度来看,通常看起来有点像:

interface Factory<T> {
    T build(Metadata d);
}

class ClientFactory implements Factory<Client> {
    Client build(Metadata d) {
        // Build actual object and return      
    }
}
Enter fullscreen mode Exit fullscreen mode

每当我需要构建一个基于配置、匹配简单接口的具体对象,并且不希望其他使用该对象的类知道发生了什么变化时,我都会尝试使用抽象工厂。是的,这句话很长。但其核心思想与其他软件工程原则的经典思想相同:信息隐藏、只做一件事的类以及小型接口。更直接地说,抽象工厂有助于隐藏构建对象的繁琐。

模式二:委托人

我相信我们都经历过这样的情况:我们不想自己做某些工作(无论是否涉及代码),而是决定将工作委托给其他人。这种情况通常发生在你在项目中的职位越高的时候——例如,项目协调员可能会将工作委托给一组助理协调员,助理协调员再将工作委托给志愿者领导,等等。

代码中的委托模式也完全一样:高阶类请求低级类替它们完成工作。这有助于高阶类保持简单,并且对其底层结构了解较少。

从代码角度来看,它看起来有点像:

interface Validator {

    bool validate(Object o);
}

class ValidatorHelper implements Validator {
    Set<Validator> delegates;

    bool validate(Object o) { 
        for (Validator v : delegates) { 
            if (!v.validate(o)) return false;
        }
        return true;
    }
}

class RestController {
    ValidationHelper helper;

    Response addObject(Object o) {
        if (helper.validate(o)) {
            return ErrorResponse
        }
        // Normal processing
    }
}
Enter fullscreen mode Exit fullscreen mode

我发现使用委托器对于验证、排序、规范化等操作非常有用。这些常见操作可能特定于特定形式的数据,但对这些数据进行决策的类可能不需要了解委托工作的全部复杂性。它只需要知道工作已经完成即可。

模式 3:构建器/命名参数

在所有改变了我代码编写方式的模式中,构建器模式是我的首选。我从一开始就用构建器编写每个 DTO(数据传输对象)。构建器实际上无需太多工作就能实现灵活且可扩展的代码,而且如果你需要的话,它还具有不可变性的优势!

其他语言可能没有(甚至不需要)构建器模式,因为它们的构造函数中有命名参数,并且具有合理的默认值。本质上,它们是相同的:只声明你希望设置为特定值的内容,其余的不用管。

在代码中,它看起来像这样:

class Dto {
    private String s;
    private int i;

    private Dto(String s, int i) {
        this.s = s;
        this.i = i;
    } 

    public static DtoBuilder builder() {
        return new DtoBuilder();
    }

    public static class DtoBuilder {  
        private String s = "some default string";
        private int i = 0;

        public DtoBuilder withString(String s) {
            this.s = s;
            return this;
        }

        public DtoBuilder withInt(int it) {
            this.i = i;
            return this;
        }

        public Dto build() {
            return new Dto(s, i);
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

注意:在 Java 中,我们也使用Lombok来完成所有繁琐的编码。

这种模式让我的代码如此简洁,是因为当你的所有对象都使用同一个构建器时,创建新的对象就变得自动化了。在 Bandwidth 的代码库中,我们总是在想要构建的类中添加一个静态工厂方法来返回构建器。之后,我们只需遵循流畅 API 的流程,传入变量,然后输入即可.build()。搞定。你无需花时间查看构造函数,甚至无需花时间查看构建器代码。它就在那里,你在编写代码时就可以使用它。在现代 IDE 中,自动完成功能会直接告诉你可以设置哪些变量。非常简单。

模式 4:丰富者

这种模式并未收录于 Go-4 书中,但它与责任链和模板方法最为密切相关。在此模式中,每条“链”都会丰富或扩充一个对象,并将该丰富后的对象返回给调用者。它可以对链中的每个丰富器执行此操作,或者,如果需要,链可以决定跳过剩余部分。

你可能会认为你违反了《代码整洁之道》中关于函数副作用的规则。我认为它没有违反这些原则,是因为增强器必须将增强后的对象返回给调用者,所以在很多方面,它声明了该对象可能会改变。对于调用者来说,它可能是一个新的对象(尤其是在不可变约束的情况下)。

interface Enricher<T> {

    T enrich(T thing);

}

class HeadersEnricher implements Enricher<Headers> {

    Headers enrich(Headers headers) {
        headers.add("x-header", "something");
        return headers;
    }
}
Enter fullscreen mode Exit fullscreen mode

我发现这种模式特别有用,尤其是在你需要用新状态来丰富一个对象的时候。例如,如果你有一个来自 Kafka 流的对象,需要在将其存储到数据仓库之前添加一些数据,那么丰富器模式就很适合。


这些只是我最喜欢的一些编写简单代码的常用模式。这绝不是一个详尽的清单,但我每天都会用它们来解决编码问题。这只是一些可以添加到你的编码工具箱中的工具。

编码愉快!


封面照片由

Unsplash上的Kelly Sikkema

鏂囩珷鏉ユ簮锛�https://dev.to/dangoslen/my-top-4-patterns-for-writing-simple-code-25pg
PREV
翻译数据库查询
NEXT
他人准则与意向谬误