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

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

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

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]删除
最新教程 更多>
  • 如何在Java字符串中有效替换多个子字符串?
    如何在Java字符串中有效替换多个子字符串?
    在java 中有效地替换多个substring,需要在需要替换一个字符串中的多个substring的情况下,很容易求助于重复应用字符串的刺激力量。 However, this can be inefficient for large strings or when working with nu...
    编程 发布于2025-06-09
  • Async Void vs. Async Task在ASP.NET中:为什么Async Void方法有时会抛出异常?
    Async Void vs. Async Task在ASP.NET中:为什么Async Void方法有时会抛出异常?
    在ASP.NET async void void async void void void void void的设计无需返回asynchroncon而无需返回任务对象。他们在执行过程中增加未偿还操作的计数,并在完成后减少。在某些情况下,这种行为可能是有益的,例如未期望或明确预期操作结果的火灾和...
    编程 发布于2025-06-09
  • 如何避免Go语言切片时的内存泄漏?
    如何避免Go语言切片时的内存泄漏?
    ,a [j:] ...虽然通常有效,但如果使用指针,可能会导致内存泄漏。这是因为原始的备份阵列保持完整,这意味着新切片外部指针引用的任何对象仍然可能占据内存。 copy(a [i:] 对于k,n:= len(a)-j i,len(a); k
    编程 发布于2025-06-09
  • 在GO中构造SQL查询时,如何安全地加入文本和值?
    在GO中构造SQL查询时,如何安全地加入文本和值?
    在go中构造文本sql查询时,在go sql queries 中,在使用conting and contement和contement consem per时,尤其是在使用integer per当per当per时,per per per当per. [&​​&&&&&&&&&&&&&&&默元组方法在...
    编程 发布于2025-06-09
  • 为什么HTML无法打印页码及解决方案
    为什么HTML无法打印页码及解决方案
    无法在html页面上打印页码? @page规则在@Media内部和外部都无济于事。 HTML:Customization:@page { margin: 10%; @top-center { font-family: sans-serif; font-weight: bo...
    编程 发布于2025-06-09
  • 在Ubuntu/linux上安装mysql-python时,如何修复\“ mysql_config \”错误?
    在Ubuntu/linux上安装mysql-python时,如何修复\“ mysql_config \”错误?
    mysql-python安装错误:“ mysql_config找不到”“ 由于缺少MySQL开发库而出现此错误。解决此问题,建议在Ubuntu上使用该分发的存储库。使用以下命令安装Python-MysqldB: sudo apt-get安装python-mysqldb sudo pip in...
    编程 发布于2025-06-09
  • eval()vs. ast.literal_eval():对于用户输入,哪个Python函数更安全?
    eval()vs. ast.literal_eval():对于用户输入,哪个Python函数更安全?
    称量()和ast.literal_eval()中的Python Security 在使用用户输入时,必须优先确保安全性。强大的Python功能Eval()通常是作为潜在解决方案而出现的,但担心其潜在风险。 This article delves into the differences betwee...
    编程 发布于2025-06-09
  • Python中嵌套函数与闭包的区别是什么
    Python中嵌套函数与闭包的区别是什么
    嵌套函数与python 在python中的嵌套函数不被考虑闭合,因为它们不符合以下要求:不访问局部范围scliables to incling scliables在封装范围外执行范围的局部范围。 make_printer(msg): DEF打印机(): 打印(味精) ...
    编程 发布于2025-06-09
  • 如何在Chrome中居中选择框文本?
    如何在Chrome中居中选择框文本?
    选择框的文本对齐:局部chrome-inly-ly-ly-lyly solument 您可能希望将文本中心集中在选择框中,以获取优化的原因或提高可访问性。但是,在CSS中的选择元素中手动添加一个文本 - 对属性可能无法正常工作。初始尝试 state)</option> < op...
    编程 发布于2025-06-09
  • 如何在GO编译器中自定义编译优化?
    如何在GO编译器中自定义编译优化?
    在GO编译器中自定义编译优化 GO中的默认编译过程遵循特定的优化策略。 However, users may need to adjust these optimizations for specific requirements.Optimization Control in Go Compi...
    编程 发布于2025-06-09
  • Python中何时用"try"而非"if"检测变量值?
    Python中何时用"try"而非"if"检测变量值?
    使用“ try“ vs.” if”来测试python 在python中的变量值,在某些情况下,您可能需要在处理之前检查变量是否具有值。在使用“如果”或“ try”构建体之间决定。“ if” constructs result = function() 如果结果: 对于结果: ...
    编程 发布于2025-06-09
  • 表单刷新后如何防止重复提交?
    表单刷新后如何防止重复提交?
    在Web开发中预防重复提交 在表格提交后刷新页面时,遇到重复提交的问题是常见的。要解决这个问题,请考虑以下方法: 想象一下具有这样的代码段,看起来像这样的代码段:)){ //数据库操作... 回声“操作完成”; 死(); } ?> ...
    编程 发布于2025-06-09
  • 为什么不````''{margin:0; }`始终删除CSS中的最高边距?
    为什么不````''{margin:0; }`始终删除CSS中的最高边距?
    在CSS 问题:不正确的代码: 全球范围将所有余量重置为零,如提供的代码所建议的,可能会导致意外的副作用。解决特定的保证金问题是更建议的。 例如,在提供的示例中,将以下代码添加到CSS中,将解决余量问题: body H1 { 保证金顶:-40px; } 此方法更精确,避免了由全局保证金重置引...
    编程 发布于2025-06-09
  • 在程序退出之前,我需要在C ++中明确删除堆的堆分配吗?
    在程序退出之前,我需要在C ++中明确删除堆的堆分配吗?
    在C中的显式删除 在C中的动态内存分配时,开发人员通常会想知道是否需要手动调用“ delete”操作员在heap-exprogal exit exit上。本文深入研究了这个主题。 在C主函数中,使用了动态分配变量(HEAP内存)的指针。当应用程序退出时,此内存是否会自动发布?通常,是。但是,即使在这...
    编程 发布于2025-06-09

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

Copyright© 2022 湘ICP备2022001581号-3