读程序员的制胜技笔记04_有用的反模式(下)

news2024/11/28 6:31:05

1. 重新发明轮子

1.1. 发明家的特质就是要用质疑的心态对待所有事物,你从未停下质疑,那你将不可避免地成为一个发明家

1.2. 并非所有的事情都有现成的轮子可以拿来用

1.3. 自己重新写一个新的API,最终调用你使用的库

1.3.1. 你的API应该是极简的,满足你的需求就可以了

1.3.1.1. 自己做自己的甲方

1.3.2. 拥有你自己的支持适配器的方便接口的方法在业界被称为适配器模式(adapter pattern)

2. SOLID原则

2.1. S:单一责任原则(single-responsibility principle)

2.1.1. 一个类应该只负责一件事

2.1.2. 不是一个类做多件事,也就是God类

2.1.3. 一个类的名字应该尽可能简洁地解释它的功能,而不是含糊不清

2.1.4. 如果名字太长或太模糊,就需要将该类拆成多个类

2.2. O:开放-封闭原则(open-closed principle)

2.2.1. 一个类应该为扩展而开放,但为修改而封闭

2.2.2. 类设计成其行为可以被外部修改

2.2.3. 可扩展性是一个设计决定,有时可能并不可取、不实用,甚至不安全

2.3. L:由芭芭拉·利斯科夫(Barbara Liskov)提出的里氏替换原则(Liskov Substitution principle)

2.3.1. 程序中的对象应该是可以在不改变程序正确性的前提下被它的子类所替换的

2.4. I:接口隔离原则(interface segregation principle)

2.4.1. 偏向于较小的、目标明确的接口,而不是泛化的、范围广泛的接口

2.4.2. 这是一个不必要的复杂和模糊的建议,甚至可以说是完全错误的

2.4.3. 分割接口不是基于范围,而是基于设计的实际需求

2.4.4. 如果单一接口不适合这项工作,请随意拆分它,而不是为了刻意满足某些定死的僵硬教条

2.5. D:依赖反转原则(dependency inversion principle)

2.5.1. 代码不应该依赖具体的实现,而应该依赖抽象

2.5.2. 继承将你绑定在一个具体的实现上,违反了该原则

2.5.3. 当你喜欢灵活性并且看到它的价值时,你更喜欢依赖抽象,而在无关紧要的情况下,你会依赖具体实现

3. 不要使用继承

3.1. 面向对象编程(Object-Oriented Programming,OOP)最强调的特点是继承

3.1.1. 在常规的继承中,普通代码和它的变化之间的关系是用父类/子类(ancestor/ descendant)模型来表达的

3.2. 从长远来看,继承带来的问题比它解决的问题要多

3.2.1. 多重继承(multiple inheritance)是首要问题之一

3.2.2. 除了多重继承之外,继承的一个更大的问题是强依赖性

3.2.2.1. 紧耦合(tight coupling)
3.2.2.2. 依赖性是万恶之源

3.3. 组合(composition)

3.3.1. 你不是从类中继承,而是在你的构造函数中接收它的抽象作为参数

3.3.2. 把你的组件看成相互拼接的乐高积木块,而不是对象的层次结构

3.3.3. 组合把共同的功能看成独立的组件

3.3.4. 组合更像是一种客户端-服务器的关系,而不是父-子关系

3.3.5. 通过它的引用来调用复用的代码,而不是在你的范围内继承它的方法

3.3.6. 把类作为参数进行接收还有一个额外的好处,那就是可以通过注入具体实现的模拟版本,让对象更加容易进行单元测试

3.3.7. 使用组合而不是继承可能需要你多写点代码

3.3.7.1. 因为你可能需要用接口而不是具体的引用来定义依赖关系,但这也会使代码摆脱依赖关系

4. 不要使用类

4.1. 类会产生少量的引用间接开销(reference indirection overhead)

4.1.1. 与值类型(value type)相比,它们更侧重间接方面

4.2. 值类型可以是有价值的

4.2.1. C#中的原始类型,如int、long和double,就是值类型

4.2.2. 可以用enum和struct这样的结构来组成你自己的值类型

4.3. enum用来保存离散的序数值(discrete ordinal value)是很不错的

4.3.1. 每一个你定义的enum的类型都是不同的,这让值拥有了类型安全(type-safe)

4.3.2. enum也是值类型,也就是说其值和整数值的传递速度是一样快的

4.4. 类会产生一点存储开销。每个类在实例化的时候都需要保留一个对象头和虚拟方法表

4.4.1. 类是在堆上分配的,而且它们会被回收

4.5. 结构是轻量级的类

4.5.1. 它们被分配在栈上,因为它们是值类型

4.5.2. 将一个结构值分配给一个变量意味着复制其内容,因为没有一个引用代表它

4.5.3. 对于任何大于指针大小的数据,复制的速度比仅传递引用的速度要慢

4.5.4. 因为结构是值类型,将它赋值给另一个结构时,会同时创建该结构所有内容的副本,而不仅仅是创建一个副本内容的引用

4.6. 在.NET中,栈的大小为1MB,而堆却可以包含TB级的数据

4.7. 栈的存取速度快,但是如果用大型结构去填充它,它很容易就被填满

4.8. 调用栈可以非常快速和有效地存储东西

4.8.1. 由于它们不受垃圾回收的影响,因此它们非常适用于处理较小的值,而且开销也较少

4.8.2. 因为它们不是引用类型,所以它们也不能为null,这使得结构不可能出现空引用异常

4.9. 你不能共享对它们的通用引用,这意味着你不能从不同的引用中更改通用实例

4.10. 当类较大时,可以提供更有效的存储,因为在赋值时只有它们的引用会被复制

4.11. 请放心地将结构用于不需要继承的小型、不可变的值类型

5. 糟糕代码

5.1. 最佳实践来自糟糕的代码,然而糟糕的代码也可能来自最佳实践的胡乱应用

5.2. 不要使用If/Else

5.2.1. If/Else让我们以一种类似于流程图的方式来表达程序的逻辑,但它也会使代码的可读性降低

5.2.2. 避免不必要缩进的一般原则是尽可能早地退出函数,并且在流程中已经暗示else语义时要避免使用else

5.2.3. “愉快路径”(happy path)

5.2.3.1. 没有其他错误发生时执行的代码部分

5.2.4. 通过将else语句转换为return语句,我们可以让读者更容易地识别愉快路径,而不是形成if语句的“俄罗斯套娃”

5.2.5. 尽早验证,并尽早返回

5.3. 使用goto

5.3.1. goto语句可以将程序的执行直接转移到一个任意的目标点

5.3.2. 许多现代编程语言不再有相当于goto语句的东西

5.3.3. C#有一个场景中非常有效:消除函数中多余的退出点

5.3.3.1. 退出点(exit point)是指函数中导致其返回给调用者的语句
5.3.3.2. 在C#中,每个返回语句都是一个退出点
5.3.3.3. 可以使用goto语句来清理,但实际上它在消除冗余方面更有优势
5.3.3.4. 如果你想在通用退出代码(common exit code)中增加更多的内容,你只需要把它添加到一个地方
5.3.3.4.1. 通过使用goto语句,我们实际上保持了代码的可读性,减少了缩进,节省了自己的时间,并使将来的修改更加容易,因为我们只需要修改一次
5.3.3.5. C# 7.0引入了局部函数,可以用来执行同样的工作,也许是以一种更容易理解的方式
5.3.3.6. 使用局部函数还允许我们在函数的顶部声明错误处理语句

6. 不写代码注释

6.1. 如果代码足够容易理解,则不需要编写代码注释

6.2. 使用那些无关的注释可能会毁掉代码的可读性

6.3. 若非必要,不写注释

6.4. 选个好名字

6.4.1. 使用HTTP、JSON、ID或者DB等广为人知的缩写倒还是可以的,但千万不要缩短单词

6.4.2. 当你选择一个描述性的名字时,你不必写一个完整的句子来解释它的功能

6.5. 充分利用函数

6.5.1. 短小的函数更易于理解

6.5.2. 尽量让函数尺寸适合开发人员的屏幕

6.5.2.1. 阅读代码时,来回滚动屏幕会让你不适,你应该一眼就能看到函数的全貌

6.5.3. 绝对不要把多个语句放在一行,一个语句至少得占用一行

6.6. 避免不必要的注释会使有用的注释像珍珠一样闪闪发光。这是使注释有用的唯一方法

6.7. 写了注释就能让你的代码很容易懂,前提是你的代码本身就精巧、易于理解

6.8. 公共API

6.8.1. 用户可能无法接触到代码

7. 要点

7.1. 避免因为混淆逻辑上的依赖界限而写出那些刚性代码

7.2. 不要害怕从头开始做一项工作,因为当你下次做的时候,你会发现进展要快得多

7.3. 请勇于拆分代码,并修整它

7.4. 保持代码最新并定期解决它所引起的问题

7.5. 重复代码而不是复用代码,避免混淆各代码逻辑的作用

7.6. 把抽象当作一项投资

7.6.1. 将抽象模型构思得巧妙一些,这样你将来写代码就会花更少的时间

7.7. 不要让使用的外部库来限制了你的设计

7.8. 为了避免将代码束缚在特定的层次结构,更推荐组合而不是继承

7.9. 尽量让代码保持自顶向下的风格,以便于阅读

7.10. 提前退出函数并避免使用else

7.10.1. return

7.11. 使用goto语句

7.11.1. 使用一个本地函数来将公共代码保存在一个地方

7.12. 避免随意、多余的注释

7.12.1. 只写有用的注释

7.13. 利用好变量和函数本身命名,让你写的代码更具可读性

7.14. 将函数划分为易于理解的子函数,以尽可能保持代码的可读性

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

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

相关文章

C++二分查找算法的应用:最小好进制

本文涉及的基础知识点 二分查找 题目 以字符串的形式给出 n , 以字符串的形式返回 n 的最小 好进制 。 如果 n 的 k(k>2) 进制数的所有数位全为1,则称 k(k>2) 是 n 的一个 好进制 。 示例 1: 输入:n “13” 输出:“3” …

Canvas制作喷泉效果示例

Canvas能制作出很多动画效果&#xff0c;下面是一个制作喷泉效果的示例 效果图 源代码 <!DOCTYPE html> <html> <head> <meta charset"utf-8"> <meta name"viewport" content"widthdevice-width, initial-scale1 ,user-…

Kubernetes技术与架构-存储 3

如上所示&#xff0c;Kubernetes集群的存储层支持不同类型的存储资源&#xff0c;其提供Projected类型的存储功能整合多种存储资源&#xff0c;将secret、downwardAPI、configMap三种不同类型的存储资源整合成一个挂载到Pod的容器实例中 如上所示&#xff0c;整合两个secret类型…

给跪!我居然被封了!

起因 前两天不知道什么情况&#xff0c;突然收到一条违规信息&#xff0c;说我营销过度&#xff1f;&#xff1f;&#xff1f; 当时一看这个立马有点慌&#xff0c;我的Python爬虫群&#xff0c;付费社群等等不是都受到影响了&#xff1f; 啥我这个号朋友圈啥的都没发&#xff…

ChatGPT 的 Text Completion

该章节我们来学习一下 “Text Completion” &#xff0c;也就是 “文本完成” 。“Text Completion” 并不是一种模型&#xff0c;而是指模型能够根据上下文自动完成缺失的文本部分&#xff0c;生成完整的文本。 ⭐ Text Completion 的介绍 Text Completion 也称为文本自动补全…

项目管理之如何估算项目工作成本

在项目管理中&#xff0c;如何估算项目工作成本是一个关键问题。为了解决这个问题&#xff0c;我们可以采用自上而下的成本限额估算法和自下而上的成本汇总估算法。这两种方法各有优缺点&#xff0c;但都可以帮助我们准确地估算项目工作成本。 自上而下的成本限额估算法 自上…

运维知识点-Docker从小白到入土

Docker从小白到入土 安装问题-有podmanCentos8使用yum install docker -y时&#xff0c;默认安装的是podman-docker软件 安装docker启动dockeryum list installed | grep dockeryum -y remove xxxx安装Docker安装配置下载安装docker启动docker&#xff0c;并设置开机启动下载所…

MySQL 表的增删查改(CRUD)

MySQL 表的增删查改(CRUD) 文章目录 MySQL 表的增删查改(CRUD)1. 新增(Create)2. 查询(Retrieve)2.1 全列查询2.2 指定列查询2.3 查询字段为表达式2.4 别名2.5 去重&#xff1a;DISTINCT2.6 排序&#xff1a;ORDER BY2.7 条件查询2.8 分页查询: LIMIT 3. 修改(Update)4. 删除(D…

Springboot3整合Mybatis-plus3.5.3报错

✅作者简介&#xff1a;大家好&#xff0c;我是Leo&#xff0c;热爱Java后端开发者&#xff0c;一个想要与大家共同进步的男人&#x1f609;&#x1f609; &#x1f34e;个人主页&#xff1a;Leo的博客 &#x1f49e;当前专栏&#xff1a; 报错以及Bug ✨特色专栏&#xff1a; …

QT在线安装所有版本,可共存(下载速度飞快)

使用最新的QT在线安装器&#xff0c;安装QT版本时只能安装5.15以及之后的版本&#xff0c;安装QT5.15之前的版本只能通过离线安装的方式&#xff0c;离线安装后还要自己去配置QT&#xff0c;离线安装还有个问题的&#xff0c;后续维护比较麻烦&#xff0c;QT的维护工具还要自己…

ubuntu中如何设置中文输入

文章目录 1.找到设置&#xff08;settings&#xff09;2.找到keyboard3.点击Chinese&#xff0c;选择intelligent pinyin&#xff0c;并点击add4.打开浏览器测试一下 1.找到设置&#xff08;settings&#xff09; 2.找到keyboard 3.点击Chinese&#xff0c;选择intelligent pin…

1+2+4+7+11+16+..x(和不超过3000),求x与式子的和

我们不难发现&#xff1a;每一项的差值成等差数列 用一个for循环&#xff0c;再用一个变量n存储等差数列 for(int i0;i<300;iin) {sumsumi;n; } 完整代码&#xff1a; #include <stdio.h> int main() {int sum 0;int i 0;int n 0;for (i 1;i < 300;i i n){…

如何在React项目中,创建令人惊叹的动画翻转卡片效果

翻转卡片是一种在网站上展示内容的动态而引人入胜的方法。翻转卡片由正面和背面两个面构成。用户可以通过点击或鼠标悬停来翻转卡片以显示更多信息。本文将向您展示如何在React中轻松构建翻转卡片。 为什么翻转卡片是您网站的有价值的补充&#xff1f; 翻转卡片可以为您的网站用…

系列五、过滤器(一)#概述

一、概述 过滤器的作用是对客户端发送给Servlet的请求以及Servlet返回给客户端的响应做一些定制化的处理&#xff0c;例如&#xff1a; &#xff08;1&#xff09;校验请求的参数是否符合逻辑&#xff0c;符合逻辑则放行&#xff0c;不符合逻辑则不允许访问方法 &#xff08;2&…

顺序栈练习

顺序栈练习 相关内容&#xff1a; 1.判断顺序栈栈满的两种方式 2.一张图理解栈顶指针加加减减的问题 3.栈的顺序存储结构&#xff08;顺序栈&#xff09; //顺序栈的初始化、判空、入栈、出栈、读取栈顶元素 //顺序栈的结构&#xff1a;数组、栈顶指针(本质是下标) #include&…

大数据毕业设计选题推荐-旅游景点游客数据分析-Hadoop-Spark-Hive

✨作者主页&#xff1a;IT毕设梦工厂✨ 个人简介&#xff1a;曾从事计算机专业培训教学&#xff0c;擅长Java、Python、微信小程序、Golang、安卓Android等项目实战。接项目定制开发、代码讲解、答辩教学、文档编写、降重等。 ☑文末获取源码☑ 精彩专栏推荐⬇⬇⬇ Java项目 Py…

使用脚手架创建项目,使用组件开发

单文件组件 单文件组件就是一个文件对应一个组件, 单文件组件的名字通常是xxx.vue(命名规范和组件名的命名规范相同),这个文件是Vue框架规定的只有它能够认识&#xff0c;浏览器无法直接打开运行 Vue框架可以将xxx.vue文件进行编译为浏览器能识别的html js css的代码 xxx.vu…

【Python基础知识一】基本语法、常用数据类型等

Python基础知识&#xff1a; 1 标识符&#xff08;Identifier&#xff09;2 关键字/保留字&#xff08;Keyword&#xff09;3 引号4 编码5 输入输出6 行与缩进7 多行语句8 注释9 数据类型9.1 数字(Number)类型9.2 变量&#xff08;variate&#xff09;9.3 字符串&#xff08;St…

【漏洞复现】Apache_HTTPD_多后缀解析漏洞

感谢互联网提供分享知识与智慧&#xff0c;在法治的社会里&#xff0c;请遵守有关法律法规 文章目录 1.1、漏洞描述1.2、漏洞复现1、基础环境2、漏洞验证 1.3、深度利用GetShell 1.4、修复建议 1.1、漏洞描述 Apache HTTPD 支持一个文件拥有多个后缀&#xff0c;并为不同后缀执…

你了解SonarQube 吗

你了解SonarQube 吗 文章目录 你了解SonarQube 吗一、介绍二、idea代码检测工具SonarLint安装方法使用方法 三、常见的Sonar解决方法Unused "private" fields should be removedSections of code should not be "commented out"Useless imports should be …