”工欲善其事,必先利其器。“—孔子《论语.录灵公》
首页 > 编程 > 了解干净的代码:系统⚡️

了解干净的代码:系统⚡️

发布于2024-11-02
浏览:944

Understanding Clean Code: Systems ⚡️

构建软件系统时,管理代码库复杂性至关重要。

Clean Code 的第 11 章讨论了设计模块化系统,这些系统随着时间的推移更容易维护和适应。

我们可以使用 JavaScript 示例来说明这些概念。


?大型系统的问题

随着系统的发展,它们自然会变得更加复杂。这种复杂性可能会导致难以:

  • 了解整个系统。
  • 进行更改而不引起意外的副作用。
  • 根据新功能或要求扩展系统。

设计良好的系统应该易于修改、可测试和可扩展。实现这一目标的秘诀在于模块化和仔细的关注点分离。


?模块化:分而治之

清洁系统设计的核心是模块化原则。通过将大型系统分解为更小的独立模块,每个模块都有明确的职责,可以使系统更易于管理。

每个模块应该封装特定的功能,使整个系统更容易理解和更改。

示例:组织购物车系统

让我们想象一下 JavaScript 中的购物车系统。您可以将系统分成几个模块,而不是将所有逻辑集中到一个文件中:

// cart.js
export class Cart {
    constructor() {
        this.items = [];
    }

    addItem(item) {
        this.items.push(item);
    }

    getTotal() {
        return this.items.reduce((total, item) => total   item.price, 0);
    }
}

// item.js
export class Item {
    constructor(name, price) {
        this.name = name;
        this.price = price;
    }
}

// order.js
import { Cart } from './cart.js';
import { Item } from './item.js';

const cart = new Cart();
cart.addItem(new Item('Laptop', 1000));
cart.addItem(new Item('Mouse', 25));

console.log(`Total: $${cart.getTotal()}`);

职责划分如下:Cart 管理商品,Item 代表产品,order.js 协调交互。

这种分离确保每个模块都是独立的,并且更容易独立测试和更改。


?封装:隐藏实现细节

模块化的目标之一是封装——向系统的其余部分隐藏模块的内部工作原理。

外部代码只能通过其定义良好的接口与模块交互。

这使得更改模块的内部实现变得更容易,而不会影响系统的其他部分。

示例:封装购物车逻辑

假设我们想要更改计算购物车总数的方式。也许现在我们需要考虑销售税。我们可以将这个逻辑封装在 Cart 类中:

// cart.js
export class Cart {
    constructor(taxRate) {
        this.items = [];
        this.taxRate = taxRate;
    }

    addItem(item) {
        this.items.push(item);
    }

    getTotal() {
        const total = this.items.reduce((sum, item) => sum   item.price, 0);
        return total   total * this.taxRate;
    }
}

// Now, the rest of the system does not need to know about tax calculations.

系统的其他部分(例如 order.js)不受总计计算方式变化的影响。这使您的系统更加灵活且更易于维护。


?关注点分离:保持责任清晰

大型系统中的一个常见问题是系统的不同部分相互纠缠。

当一个模块开始承担太多职责时,在不同的上下文中更改或重用就会变得更加困难。

关注点分离原则确保每个模块都有一个特定的职责。

示例:单独处理付款

在购物车示例中,付款处理应在单独的模块中处理:

// payment.js
export class Payment {
    static process(cart) {
        const total = cart.getTotal();
        console.log(`Processing payment of $${total}`);
        // Payment logic goes here
    }
}

// order.js
import { Cart } from './cart.js';
import { Payment } from './payment.js';

const cart = new Cart(0.07); // 7% tax rate
cart.addItem(new Item('Laptop', 1000));
cart.addItem(new Item('Mouse', 25));

Payment.process(cart);

现在,支付逻辑与购物车管理分离。这使得以后可以轻松修改支付流程(例如,与不同的支付提供商集成),而不会影响系统的其余部分。


?独立测试模块

模块化的最大好处之一是您可以独立测试每个模块。

在上面的示例中,您可以为 Cart 类编写单元测试,而无需担心付款的处理方式。

示例:对购物车进行单元测试

// cart.test.js
import { Cart } from './cart.js';
import { Item } from './item.js';

test('calculates total with tax', () => {
    const cart = new Cart(0.05); // 5% tax
    cart.addItem(new Item('Book', 20));

    expect(cart.getTotal()).toBe(21);
});

通过清晰的关注点分离,每个模块都可以单独测试,使调试更容易,开发更快。


?处理依赖关系:避免紧耦合

当模块彼此过于依赖时,系统某一部分的变化可能会在其他地方产生意想不到的后果。

为了最大限度地减少这种情况,目标是模块之间的松散耦合。

这允许每个模块独立发展。

示例:注入依赖项

不要将依赖项硬编码在模块内,而是将它们作为参数传递:

// cart.js
export class Cart {
    constructor(taxRateCalculator) {
        this.items = [];
        this.taxRateCalculator = taxRateCalculator;
    }

    addItem(item) {
        this.items.push(item);
    }

    getTotal() {
        const total = this.items.reduce((sum, item) => sum   item.price, 0);
        return total   this.taxRateCalculator(total);
    }
}

这种方法使 Cart 类更加灵活,并且更容易使用不同的税收计算进行测试。


结论:保持系统模块化、灵活且易于更改

快乐编码! ?

版本声明 本文转载于:https://dev.to/alisamir/understanding-clean-code-systems-53da?1如有侵犯,请联系[email protected]删除
最新教程 更多>

免责声明: 提供的所有资源部分来自互联网,如果有侵犯您的版权或其他权益,请说明详细缘由并提供版权或权益证明然后发到邮箱:[email protected] 我们会第一时间内为您处理。

Copyright© 2022 湘ICP备2022001581号-3