<代码整洁之道>精彩片段整理

news2024/11/28 1:51:08

最近在读这本<代码整洁之道>,感觉里面有很多内容都很有启发。整理下来,大家一起看下,顺便看看作者说的有没有道理。这本书的作者是:罗伯特丶马丁,大家经常叫他鲍勃大叔。下面直接进入正题,先看一下目录

文章目录

  • 1、有意义的命名
    • 1.1、变量的命名
    • 1.2、方法的命名
    • 1.3、类名
  • 2、方法的编写
    • 2.1、单一职责原则
    • 2.2、方法中的逻辑要属于一个层级
    • 2.3、不要把返回值作为方法的入参
    • 2.4、方法入参个数
    • 2.5、方法入参类型
    • 2.6、尽量使用异常,少用错误码
    • 2.7、方法中多用return、continue、goto
  • 3、注释
    • 3.1、好的注释
      • 3.1.1、作者的一个重要决策
      • 3.1.2、强调逻辑的重要性
      • 3.1.3、//todo、//fixme注解的使用
    • 3.2、坏的注释
      • 3.2.1、含糊不清的注释
      • 3.1.2、没有任何用处的注释
      • 3.1.3、太长的注释
  • 4、错误处理
    • 4.1、使用未受检异常
    • 4.2、手动抛出的异常要提供足够的上下文
    • 4.3、对异常进行分类
    • 4.4、特例对象简化调用端逻辑
    • 4.5、方法出参不要返回null,方法入参不要传递null
  • 5、边界

1、有意义的命名

这一章主要分成三个小部分。

1.1、变量的命名

主要讲究的就是见名知意,不要随便写一个 abc之类的看不懂意图的名称,会给阅读这段代码的同学造成困扰,同时这种abc的名称也不易检索。另外注意,不要用一些具有误导性的词汇。

1.2、方法的命名

方法一般都讲究单一职责,所以我们是可以根据方法的内容来凝练出一个词语或一个词组来表达这个方法的作用

1.3、类名

一般是名词

2、方法的编写

这一张主要分成三个小部分

2.1、单一职责原则

单一职责原则很好的体现了java的封装原则,一个方法,只做一件事。这样做有两个好处,方法的可复用性强,另外,方法很好阅读。

2.2、方法中的逻辑要属于一个层级

这一段内容,我认为是对单一职责原则的补充。一个方法中,是可能会遇到有多段逻辑的情况,但是这些逻辑做的事需要是一个层级的。比如:小品里说的,要把大象装冰箱,总共分几步?三步。这三步,其实都是围绕着大象装冰箱这个事来的。切忌不能在方法中做一些和主逻辑不相干的事。

2.3、不要把返回值作为方法的入参

这一点,我自己是要反思的,我经常会从外面new一个list,或者对象啥的,通过入参传递到方法中,在方法中改动这个对象。这种方式能避免就避免

2.4、方法入参个数

方法入参越少越好,最好没有入参,尽量不要超过3个,超过3个入参,会让方法理解起来很困难。如果超过了3个,最好采用一些封装的手段,将参数封装到一个对象中,然后方法的参数传递这个对象。
比如:原方法签名为:writeField(OutputStream outputStream,name)
这是一个两参数方法,如何减少方法入参个数呢?
我们可以新定义一个FieldWriter类

public class FieldWriter {
    private OutputStream outputStream;
    
    public void write(String name){
        ........
    }
}

然后在原来引用writeField方法的地方,替换为fieldWriter.write(name),这样就利用面向对象的思想将outputStream封装到了类中,减少了方法参数的个数

2.5、方法入参类型

尽量不要入参布尔类型,更不要将布尔类型作为方法内部变更逻辑的标志

2.6、尽量使用异常,少用错误码

如果我们使用异常码的话,方法的调用方需要在逻辑中进行一系列的判断。如果方法新增了错误码,调用方很有可能需要跟着改
在这里插入图片描述
但如果用异常的话,我们可以把逻辑简化成下面这样
在这里插入图片描述
这个点,我觉着值得商榷,书上这样的写法,是不关心异常的写法,如果调用方需要根据方法的返回来做不同的逻辑呢?还是要捕获不同异常,来做不同的逻辑。
我觉着作者想表达的思想就是,让方法的调用者处理起来逻辑要简单。我们不要照抄他的说法,多学习他的思想

2.7、方法中多用return、continue、goto

不要一个逻辑写到底,在需要返回的地方,直接返回就可以了,其他人在阅读这段代码的时候,他就很容易知道,逻辑的终止点,梳理起来要容易

3、注释

按照书中作者的说法,如果我们需要给一个方法加注释,自己应该感到羞耻。加注释就意味着,方法的逻辑复杂,我们担心其他人看不懂,所以需要专门说明一下。我觉着作者的想法是有道理的,但也不是说不能用注释,作者就给列举了几个应该用注释的场景,以及如何写好注释

3.1、好的注释

3.1.1、作者的一个重要决策

比如一段算法的改进,我们可以加一个注释,说明一下我们的设计思路,使用的场景之类,这样读者可以更容易的掌握这段算法

3.1.2、强调逻辑的重要性

我们可能会写一些看似无关紧要的逻辑,如果我们担心其他人改动的时候,影响到这段逻辑,此时可以加一些注释,提醒一下。

3.1.3、//todo、//fixme注解的使用

我们要注意使用这两个特殊的注释,来表明我们将来要做的事,或者目前是一个临时的写法,未来可以改进到更好

3.2、坏的注释

3.2.1、含糊不清的注释

比如下面这段方法,这是一个著名开源项目中的一个代码片段
在这里插入图片描述
在捕获到IOException后,源码作者写了一个注释:
//No properties files means all defaults are loaded
针对这段注释,鲍勃大叔发起了一系列追问
1)、谁来加载默认的配置
2)、调用loadedProperties.load方法的时候,默认配置加载完了吗?
3)、捕获到IOException异常后,作者没有做任何的处理,就只写了一个注释,那作者是觉着不用处理,还是后面会继续处理?
这段注释能被人问出这么多问题,就证明注释写的非常失败

3.1.2、没有任何用处的注释

下面的这几个例子,就是纯纯的废话,没有提供任何有用的信息。我们完全可以使用一个有意义的变量来替代注释
在这里插入图片描述

3.1.3、太长的注释

下面这个注释,说实话,我是不想读的。太长了
在这里插入图片描述

4、错误处理

4.1、使用未受检异常

我们先看一下受检异常,受检异常,如果不捕获,程序编译会失败。我们常见的IOException,就是受检异常。
未受检异常,比如:RuntimeException。不捕获,程序可以正常编译。
使用未受检异常,代码看起来更清爽

4.2、手动抛出的异常要提供足够的上下文

足够的上下文,其实就是我们平时所说的堆栈信息。方法报错,如果能看到完整的堆栈,方法的调用者很快就能定位到问题

4.3、对异常进行分类

未分类前
在这里插入图片描述
需要捕获各种异常,看着很乱。
我们可以对异常进行一些分类,如下:
在这里插入图片描述
可以看到,我们构建出了一个PortDeviceFailure异常。然后在LocalPort类的open方法中,对各种异常进行了分类,和PortDeviceFailure异常属于一类的异常,都统一抛出PortDeviceFailure异常

4.4、特例对象简化调用端逻辑

我们看下面的一段代码。
如果未捕获到异常,调用MealExpenses的getTotal方法。
如果捕获到MealExpensesNotFound异常,调用getMealPerDiem方法
在这里插入图片描述
我们可以考虑使用多态 + 特例的方式简化以上逻辑
在这里插入图片描述
可以看到我们将getMealPerDiem方法封装成了PerDiemMealExpenses对象。如果抛出了MealExpensesNotFound异常,我们就返回PerDiemMealExpenses对象,就类似下面的处理方式

public class ExpenseReportDao {
    MealExpenses getMeals(String id) {
        try {
            return new NormalMealExpenses();
        } catch (MealExpensesNotFound e) {
            return new PerDiemMealExpenses();
        }
    }
}

这样,调用端的逻辑就不需要在捕获MealExpensesNotFound的异常,直接调用getMeals(String id)方法拿到MealExpenses对象,然后调用其getTotal方法就可以了

MealExpenses mealExpenses = expenseReportDao.getMeals(employee.getID());
m_total += mealExpenses.getTotal();

这样,方法调用者的处理逻辑就简化了很多。

4.5、方法出参不要返回null,方法入参不要传递null

这个很好理解,如果随意返回null或者入参有null,我们就需要判空,众所周知,判空的代码,很丑陋。

public class MetricsCalculator{
	public double xProjection(Point p1,Point p2){
		if(p1 == null){
			throw new IllegalArgumentException("P1 should not be null")
		}
		if(p2 == null){
			throw new IllegalArgumentException("P2 should not be null")
		}
		......
	}
}

考虑使用断言
在这里插入图片描述
断言要比传统的判断,形式上更美观一些。

5、边界

边界的理解就是:我们要将方法调用者不关心的部分封装到方法内部,不要让方法的调用者感知到,本质上还是面向对象的思想
看下面的例子

Map sensors = new HashMap();
Sensor s = (Sensor)sensors.get(sensorId);

这样的代码,相信你看到并不会陌生,这是一个强制类型转换的逻辑。
你可能会说,可以给Map加一个Sensor的泛型,这样就可以不用强转了,但是Map里可以放很多东西,不一定只放Sensor类型,如果放了其他类型,那Map的泛型就只能是Object类型,强转不可避免。
此时,我们可以考虑封装一个Sensor类

public class Sensors{
	private Map sensors = new HashMap();
	
	public Sensor getById(String id){
		return (Sensor)sensors.get(id);
	}
	...
}

持续更新…

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1450650.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【开源】新生报到网站 JAVA+Vue.js+SpringBoot+MySQL

本文项目编号&#xff1a; T 002 。 \color{red}{本文项目编号&#xff1a;T002。} 本文项目编号&#xff1a;T002。 目录 1 功能模块1.1 在线交流模块1.2宿舍分配模块1.3 校园概况模块1.4 专业管理模块 2 系统展示3 核心代码3.1 图表展示3.2 查询评论3.3 新增报道 4 免责声明 …

【实战】一、Jest 前端自动化测试框架基础入门(一) —— 前端要学的测试课 从Jest入门到TDD BDD双实战(一)

文章目录 一、前端要学的测试课1.前端要学的测试2.前端工程化的一部分3.前端自动化测试的例子4.前端为什么需要自动化测试&#xff1f;5.课程涵盖内容6.前置技能7.学习收获 二、Jest 前端自动化测试框架基础入门1. 自动化测试背景及原理前端自动化测试产生的背景及原理 2.前端自…

嵌入式培训机构四个月实训课程笔记(完整版)-Linux ARM驱动编程第四天-ARM Linux编程之IIC与uart (物联技术666)

链接&#xff1a;https://pan.baidu.com/s/1V0E9IHSoLbpiWJsncmFgdA?pwd1688 提取码&#xff1a;1688 教学内容&#xff1a; 1、I2C总线&#xff1a; I2C&#xff08;Inter&#xff0d;Integrated Circuit),PHILIPS公司开发的两线式半双工同步串行总线&#xff1b;可以用来连…

[职场] 汉语言文学求职信范文 #微信#笔记

汉语言文学求职信范文 在撰写求职信之前一定要明确自己写信的目的&#xff0c;然后&#xff0c;在撰写过程中&#xff0c;朝着这个目的前进。其次&#xff0c;撰写求职信的时候一定要包含自己的竞争优势&#xff0c;用相应的数据或者故事讲述&#xff0c;切记空谈阔论。最后&am…

LeetCode Python - 19.删除链表的倒数第N个结点

目录 题目答案运行结果 题目 给你一个链表&#xff0c;删除链表的倒数第 n 个结点&#xff0c;并且返回链表的头结点。 示例 1&#xff1a; 输入&#xff1a;head [1,2,3,4,5], n 2 输出&#xff1a;[1,2,3,5] 示例 2&#xff1a; 输入&#xff1a;head [1], n 1 输出&a…

漫漫数学之旅022

文章目录 经典格言数学习题古今评注名人小传- 刘易斯卡罗尔 经典格言 艾丽斯笑着说&#xff1a;“去尝试也毫无用处&#xff0c;一个人无法相信不可能的事情。”——刘易斯卡罗尔&#xff08;Lewis Carroll&#xff09;《艾丽斯梦游仙境&#xff08;Alice in Wonderland&#…

[OPEN SQL] 新增数据

INSERT语句用于数据的新增操作 本次操作使用的数据库表为SCUSTOM&#xff0c;其字段内容如下所示 航班用户(SCUSTOM) 该数据库表中的部分值如下所示 1.插入单条数据 语法格式 INSERT <dbtab> FROM <wa>. INSERT INTO <dbtab> VALUES <wa>. INSERT &…

紫微斗数双星组合:廉贞天府在辰戌

文章目录 前言内容总结 前言 紫微斗数双星组合&#xff1a;廉贞天府在辰戌 内容 紫微斗数双星组合&#xff1a;廉贞天府在辰戌 性格分析 廉贞天府同坐辰、戌宫&#xff0c;若无煞星冲破&#xff0c;为“天府朝垣格”&#xff0c;也为“府相朝垣格”&#xff0c;富贵双全&am…

RT-Thread(RTT)如何打印输出浮点数

问题&#xff1a; 一、基于RTT的工程下&#xff0c;打印输出浮点数 二、输出的都是这些&#xff0c;因为RTT默认下不支持输出浮点数 解决&#xff1a; 一、点击RT-Thread Settings 二、点击添加软件包 三、输入print &#xff0c;搜索后添加rt_vsnprintf_full这个 四、添加后…

Python 中实现线性搜索算法

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站零基础入门的AI学习网站~。 前言 线性搜索算法&#xff0c;也称为顺序搜索算法&#xff0c;是一种简单但常用的搜索技术&#xff0c;用于查…

Pytest测试技巧之Fixture:模块化管理测试数据

在 Pytest 测试中&#xff0c;有效管理测试数据是提高测试质量和可维护性的关键。本文将深入探讨 Pytest 中的 Fixture&#xff0c;特别是如何利用 Fixture 实现测试数据的模块化管理&#xff0c;以提高测试用例的清晰度和可复用性。 什么是Fixture&#xff1f; 在 Pytest 中&a…

AI算法参数个数本身优化空间

一、背景 AI算法的参数数量并非越多越好&#xff0c;也不是越少越好。参数的数量与模型的复杂度密切相关&#xff1a; 1. 参数多&#xff08;高复杂度模型&#xff09;&#xff1a; - 优点&#xff1a;模型具有更强的表达能力和拟合能力&#xff0c;对于复杂的、非线性的数据分…

09、全文检索 -- Solr -- SpringBoot 整合 Spring Data Solr (生成DAO组件 和 实现自定义查询方法)

目录 SpringBoot 整合 Spring Data SolrSpring Data Solr的功能&#xff08;生成DAO组件&#xff09;&#xff1a;Spring Data Solr大致包括如下几方面功能&#xff1a;Query查询&#xff08;属于半自动&#xff09;代码演示&#xff1a;1、演示通过dao组件来保存文档1、实体类…

GPU独显下ubuntu屏幕亮度不能调节解决方法

GPU独显下屏幕亮度不能调节&#xff08;假设你已经安装了合适的nvidia显卡驱动&#xff09;&#xff0c;我试过修改 /etc/default/grub 的 GRUB_CMDLINE_LINUX_DEFAULT"quiet splash acpi_backlightvendor" &#xff0c;没用。修改和xorg.conf相关的文件&#xff0c;…

C++ 双向广度搜索,嚯嚯!不就是双指针理念吗

1. 前言 在线性数据结构中搜索时&#xff0c;常使用线性搜索算法&#xff0c;但其性能偏低下&#xff0c;其性能改善方案常有二分搜索和双指针或多指针搜索算法。在复杂的数据结构如树和图中&#xff0c;常规搜索算法是深度和广度搜索。在深度搜索算法过程中常借助剪枝或记忆化…

掌握Go并发:Go语言并发编程深度解析

&#x1f3f7;️个人主页&#xff1a;鼠鼠我捏&#xff0c;要死了捏的主页 &#x1f3f7;️系列专栏&#xff1a;Golang全栈-专栏 &#x1f3f7;️个人学习笔记&#xff0c;若有缺误&#xff0c;欢迎评论区指正 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&…

高程 | 数据的共享与保护(c++)

文章目录 &#x1f4da;标识符的作用域与可见性&#x1f407;作用域&#x1f407;可见性 &#x1f4da;对象的生存期&#x1f407;静态生存期&#x1f407;动态生存期 &#x1f4da;类的静态成员&#x1f407;静态数据成员&#x1f407;静态函数成员 &#x1f4da;类的友元&…

什么是位段?位段的作用是什么?他与结构体有什么关系?

目录 1.什么是位段&#xff1f; 2.位段的内存分配 判断当前机器位段的内存分配形式 1.什么是位段&#xff1f; 位段的声明和结构是类似的&#xff0c;有两个不同&#xff1a; 1.位段的成员必须是 int、unsigned int 或signed int或char 。 2.位段的成员名后边有一个冒号和…

相机图像质量研究(13)常见问题总结:光学结构对成像的影响--鬼影

系列文章目录 相机图像质量研究(1)Camera成像流程介绍 相机图像质量研究(2)ISP专用平台调优介绍 相机图像质量研究(3)图像质量测试介绍 相机图像质量研究(4)常见问题总结&#xff1a;光学结构对成像的影响--焦距 相机图像质量研究(5)常见问题总结&#xff1a;光学结构对成…

STM32 I2C

目录 I2C通信 软件I2C读写MPU6050 I2C通信外设 硬件I2C读写MPU6050 I2C通信 R/W&#xff1a;0写1读 十轴&#xff1a;3轴加速度&#xff0c;3轴角速度&#xff0c;3轴磁场强度和一个气压强度 软件I2C读写MPU6050 MyI2C.c #include "stm32f10x.h" …