代码整洁之道重点选摘_代码整洁之道读后感

代码整洁之道重点选摘_代码整洁之道读后感用了很久的摸鱼时间,才把《代码整洁之道》看完。不得不承认自己平时写代码真的很随意,随着工作中CodeReview的深入,才越来越觉得之前的自己是

代码整洁之道重点选摘_代码整洁之道读后感

前言

用了很久的摸鱼时间,才把《代码整洁之道》看完。不得不承认自己平时写代码真的很随意,随着工作中CodeReview的深入,才越来越觉得之前的自己是多么渺小,总觉得所谓优雅的代码是哗众取宠。

这篇文章,算是我对整本书的一个归纳,很多细节着实能让我们写出漂亮的代码,至少不会让同事看到就想骂:什么xx代码!

当然什么样是好的代码,谁也说不清,我在读这本书的时候也产生很多的疑问,文中也有些内容并没有给出正面的解释。不过这不妨碍我们取其精华。

正所谓:尽信书,不如无书。

正文

一、命名

  • 命名有意义
    • a、b、c…这种命名没有任何意义
  • 不加废话
  • ProductInfo:Info就是废话(Info没啥意义)
    • nameString:String就是废话(name不会有int型)
  • 不用俚语、双关等文学上的东西
  • 合理的包装变量
    • 例如:某几个变量是用来描述一种业务。那么可以用对应业务的class来封装这几个变量
  • 可供搜索的命名
    • 全局搜索MAX_LASSES_PER_STUDENT,总比搜索7要容易

二、函数

  • 只做一件事(单一职责原则SRP)
    • 合理情况:拆成两个方法。一个checkUserName()检查字段(询问);一个setAttitude()设置字段(指令)
    • 这一件事指:另一抽象维度下的逻辑,有可能是多个,但要是同一维度
    • 每一个函数,代表着一个抽象维度
    • 阅读代码,就可以自顶向下,高维度 -> 低纬度 的顺序阅读
    • 分隔 指令与询问
    • if(set(“username))…这一个set方法,涵盖了两层含义:set “username”,并且如果set成功返回true。
  • switch
    • 尽可能用多态替换switch
    • switch尽可能埋在抽象程度高的模块中
  • 参数
    • 尽可能的少(比如没有参数)
  • 无副作用
    • 例如:check账号密码是否匹配的方法,内部实现不应该偷摸地执行其他逻辑,比如初始化某个页面,这不职责单一。
  • 输出型参数
    • 避免使用有有疑惑性的输出型参数。
    • 例如:appendFooter(s)。仅凭函数名无法确认是把s添加到谁的后面,或者把谁添加到s后面。应该改成:s.appendFooter():就能明白是给s添加一些footer
  • 用异常代替返回错误码
    • 对补充分隔 指令与询问
    • 错误码意味了有可能存在一个方法涵盖多层含义,这种case下可以使用异常来代码错误码
  • 注释
    • 应该用好的函数风格来注释代码
  • 暗含时序性的函数,应该显示的设计函数签名,比如B函数的入参是A函数的出参

三、对象和数据结构

  • 有针对性的private/public
  • 数据结构和对象的对立
    • 数据结构:暴露数据
    • 对象:封装数据,暴露操作数据的函数
  • 面对对象和面向过程的对立
    • 面向对象:多态意味着想在接口上增加函数是困难的,需要改所有的实现
    • 面向过程:没有多态特性,意味着代码都要强依赖数据结构,因此增加数据结构是困难的。需要修改所有依赖数据结构的地方
    • 二者应该相辅相成
  • Demeter定律 (最少知识原则)
    • 函数不应该调用有任何函数返回的对象的方法
    • 数据结构除外,数据结构就是对外暴露细节
    • 通俗解释:人可以命令一条狗行走,但是不应该直接指挥狗的腿行走,应该由狗去指挥控制它的腿如何行走。
    • 问题由来:类与类之间的关系越密切,耦合度越大,当一个类发生改变时,对另一个类的影响也越大。
    • 好处:降低耦合

四、错误处理

  • 用异常代替错误状态码
    • 收敛错误逻辑
    • 避免遗忘错误逻辑(throw异常,强制提醒)
  • 使用运行时异常(?)
    • 非运行时异常,要么try要么throw,因此就意味着较底层的方法throw一个异常,整个引用链都得进行修改
    • PS:个人认为,有些时候throw异常是有必要的,需要显示的告诉调用者,这里有异常。
  • 充分的错误信息
  • 收敛三方异常
    • 自定义一个异常用于收敛外部的异常
    • 逻辑收敛,以后发生改动也只需要改动收敛的代码即可
  • 不返回null
    • 返回默认值或者抛异常
    • 同样也不随意传入一个null

五、类

  • 类的名称就已经能够预见类的职责
    • 不建议用很大scope的命名,比如:Manager
  • 单一职责
  • 内聚
    • 依赖更少的外部信息(如方法入参少)
    • 暴露更少的public方法
    • 保证单一职责情况下,尽可能的内聚
    • 类逻辑爆炸,就意味着需要按职责拆更多的独立类
  • 开闭原则
    • 对拓展开放,对修改关闭
  • 依赖倒置
    • 依赖抽象,而不是依赖实现

六、系统

  • 构造与使用分离
    • 下图:把LineItem实例的实例化拆到OrderProcessing中,脱离业务代码main。而LineItem的实现由业务代码main实现。
    • 依赖注入(控制反转)
    • 服务发现就是一种依赖注入思想的实现,将实例化的过程交给服务发现框架去处理
    • 好处就是按需加载。按需的逻辑都抽到了注入模块
  • AOP(面向切面编程)
    • 切面
    • 如何理解切面:独立的能力,比如:日志(此语境下的面向切面,也就是说面向日志)
    • 横向
    • 如何理解横向:业务代码从面向对象的角度,它属于纵向的形式(层层调用)。那么对于对应我们的切面就是横向的。在合适的切点上横向的贯穿进整个需要的切面业务代码中。
    • 好处
    • 整个切面是一个独立模块,那么无侵入地将切面代码织入到业务代码的特定切点上。既能解耦/分离关注点,又保证了合理的内聚。
  • 避免传递依赖
    • 比如A依赖B,B依赖C;A不应该了解C

七、重构

  • 不可重复(封装 + 复用)
    • 设计模式:模板方法(基类定义公用的方法调用逻辑,基类实现具体方法)
    • 由小规模复用上升到大规模复用
    • 移除高纬度的依赖
  • 表达
    • 用代码描述逻辑,而不是靠约定/注释等

八、并发

  • 一种解耦策略:把目的和时机解耦
  • 执行模型
    • 生产者-消费者模型
    • 读者-作者模型
    • 多对一
    • 作者线程更新频率慢,会导致读者线程大规模等待
    • 宴会哲学家
    • 资源竞争(死锁等问题)
  • 保持同步区域尽可能的小

九、逐步改进

  • 在迭代过程之中,找到可以抽象出来的模块
  • 要有魄力,该重构就重构(局部)
  • 原则:高速上换轮子。(不改变其结构)

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
转载请注明出处: https://daima100.com/4199.html

(0)
上一篇 2023-04-02 12:30
下一篇 2023-04-01

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注