大家好,我是考100的代码小小顾,祝大家学习进步,加薪顺利呀。今天说一说代码整洁之道重点选摘_代码整洁之道读后感,希望您对编程的造诣更进一步.
前言
用了很久的摸鱼时间,才把《代码整洁之道》看完。不得不承认自己平时写代码真的很随意,随着工作中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