企业网站建设如何去规划,dedecms导购网站模板,南京app开发公司排名,图片展示网站搭建# 零、学习计划
* 数据库相关 * 索引 * [我以为我对数据库索引很了解#xff0c;直到我遇到了阿里面试官 - 知乎 (zhihu.com)](https://zhuanlan.zhihu.com/p/107487215) * [给我一分钟#xff0c;让你彻底明白MySQL聚簇索引和非聚簇索引 - 知乎 (zhihu.com)](ht…# 零、学习计划
* 数据库相关 * 索引 * [我以为我对数据库索引很了解直到我遇到了阿里面试官 - 知乎 (zhihu.com)](https://zhuanlan.zhihu.com/p/107487215) * [给我一分钟让你彻底明白MySQL聚簇索引和非聚簇索引 - 知乎 (zhihu.com)](https://zhuanlan.zhihu.com/p/142139541) * [聚集索引聚类索引与非聚集索引非聚类索引 - 知乎 (zhihu.com)](https://zhuanlan.zhihu.com/p/86189418) * [(2 封私信 / 6 条消息) 索引是什么 - 知乎 (zhihu.com)](https://www.zhihu.com/question/408010643) * 存储引擎 * [一张图让你看懂InnoDB (360doc.com)](http://www.360doc.com/content/18/0523/10/45882429_756316759.shtml) * 事务 * 解析、优化、执行等过程 * [mysql脏页是什么 - 知乎 (zhihu.com)](https://zhuanlan.zhihu.com/p/155799967) * 数据结构 * 数据库相关结构体B树、B树、红黑树.... * [如何系统地学习数据结构与算法 - 知乎 (zhihu.com)](https://zhuanlan.zhihu.com/p/137041568) * [红黑树超强动静图详解简单易懂_吴师兄学算法 (cxyxiaowu.com)](https://www.cxyxiaowu.com/15707.html) * [完全二叉树的节点数你真的会算吗 (qq.com)](https://mp.weixin.qq.com/s/xW2fbE3v4JhMSKfxoxIHBg) * 算法 * [leecode564. 寻找最近的回文数-困难题目 - 知乎 (zhihu.com)](https://zhuanlan.zhihu.com/p/153481582) * 网络通信 * [15w字的计算机网络知识核心总结再也不怕面试官问我网络知识了飘了_小林coding的技术博客_51CTO博客](https://blog.51cto.com/u_14888059/3804983) * [突击大厂面试图解网络开放下载 (qq.com)](https://mp.weixin.qq.com/s/_23WhJ9bOV9vjRq5EXsaXA) * [答应我这次搞懂 I/O 多路复用_小林coding的博客-CSDN博客](https://blog.csdn.net/qq_34827674/article/details/115619261) * 锁 * [无锁编程基础与代码实现 - 知乎 (zhihu.com)](https://zhuanlan.zhihu.com/p/450105677) * [SQL Server里的闩锁介绍 - Woodytu - 博客园 (cnblogs.com)](https://www.cnblogs.com/woodytu/p/4673814.html) * 性能相关 * [面试官如何写出让 CPU 跑得更快的代码_51CTO博客_写代码吃cpu吗](https://blog.51cto.com/u_14888059/3789791) * TLB miss与cache miss * [TLB缓存是个神马鬼如何查看TLB miss - 知乎 (zhihu.com)](https://zhuanlan.zhihu.com/p/79607142) * [Cache原理简介及cache miss_cache miss rate_hithj_cainiao的博客-CSDN博客](https://blog.csdn.net/hithj_cainiao/article/details/117354903) * 计算机相关 * [浮点数的二进制表示 - 阮一峰的网络日志 (ruanyifeng.com)](https://www.ruanyifeng.com/blog/2010/06/ieee_floating-point_representation.html) * 内存管理 * Linux内存管理[linux内存管理---虚拟地址、逻辑地址、线性地址、物理地址的区别一_鱼思故渊的博客-CSDN博客](https://blog.csdn.net/yusiguyuan/article/details/9664887) * [Linux内存管理 -- /proc/{pid}/smaps讲解 - 简书 (jianshu.com)](https://www.jianshu.com/p/8203457a11cc) * [Linux 内存管理 - 简书 (jianshu.com)](https://www.jianshu.com/p/fb345b94501f) * 优秀博主 * [小林coding的博客_CSDN博客-图解计算机网络,图解操作系统,图解MySQL领域博主](https://blog.csdn.net/qq_34827674/article/list/4)
# 一、计算机相关
### 1. cache miss
### 2. TLB miss
# 二、Linux
### 1. 基础命令
##### 1.1 so相关
shell # 查看.so导出函数 nm -D **.so可加grep objdump -tT **.so # 查看哪些so导出了指定函数 find / -name *.so | xargs nm -AD | grep T usleep
##### 1.2 文件文本相关
shell # 搜索多个文件里面的字符串 grep -niR check_argument build/*.sh find -type f -name *.sh |xargs grep check_arguments # 查找匹配行及显示它上下n行 cat xxx.txt |grep str -C 10
##### 1.3 vi命令
shell # 字符串替换 :%s/gmdb-kvlite/GMDB-Lite/g
:%s/GmcYangTreeNodeT/GmcYangNodeT/g
##### 1.4 压缩、解压相关
shell # tar.gz 压缩 tar -zcvf xxx.tar.gz xxx/ # rpm 解压 rpm2cpio xxx.rpm | cpio -di
##### 1.5 查看进程、线程
shell # 查看线程 ps -T -p pidof fwmd
##### 1.6 远程scp
shell scp local_file remote_usernameremote_ip:remote_file
### 2. C编程
##### 2.1 占位符的使用
| 数据类型 | 格式化符号 | 说明 | | -------- | ---------------------------------------- | ------------------------------------------------------------ | | uint64_t | PRIu64 | 在x86下使用%llu在x86_64下对应%lu不同场景尽量使用一致的打印 | | uint32_t | PRIu32 | 为了保持写法一致推荐使用PRI*系列 | | int64_t | PRId64 | 同上 | | int32_t | PRId32 | 同上 | | size_t | %zu | sizeof、strlen返回都是size_t需使用%zu否则在不同平台上容易编译报错 | | 枚举变量 | 对枚举增加强转再使用匹配的类型打印 | 在C标准对枚举的长度没有准确定义甚至是有符号还是无符号可能都有不一致。复杂打印它的格式化转换需要注意 | | 枚举常量 | 根据枚举值选择如有符号用%d无符号用%u | 常量编译后直接在代码段不用强转 | | long | | 编译跨平台的软件时尽量不要使用long类型或者需要对long类型做特殊处理 |
### 3. GLIBC版本
查看GLIBC版本号
shell # libc.so打印信息中包含有版本号 /lib64/libc.so.6 # lib.so通常支持多个版本即向前兼容查看该文件中包含的字符串可以看到其支持的版本通常是连续的 strings /lib64/libc.so.6 |grep GLIBC # ldd是glibc提供的命令 ldd --version # getconf GNU_LIBC_VERSION getconf GNU_LIBC_VERSION
编码中的预编译宏判断版本号
c #if __GLIBC__ 2 __GLIBC_MINOR__ 30
### 4. 共享内存
shell # 清理共享内存 ipcrm -a # 查看共享内存 ipcs
### 5. 进程状态
| 状态 | 描述 | | ---- | ------------------------------------ | | O | 进程正在处理器运行这个状态很少见 | | S | 休眠状态sleep | | R | 进程处于运行或就绪状态 | | I | 空闲状态idle | | Z | 僵尸状态zombie | | T | 跟踪状态traced | | B | 进程正在等待更多的内存页 | | D | 不可中断的深度睡眠 |
# 三、shell
### $用法
shell # 命令替换括号或者反引号 $(pwd) $pwd
# 变量替换$var和${var}本质上相同但后者会精确变量名的范围 Ahello A_1$AB # A_1值为空因为没有名字为AB的变量 A_2${A}B # A_2值为helloB
# 其他用法 $0 # shell本身文件名 $? # 最后运行命令的返回值 $! # shell最后运行的后台process的PID $$ # shell本身的pid $# # shell的参数个数 $ # 所有参数列表 以$1 $2 … $n的形式输出所有参数此选项参数可超过9个 $* # 所有参数列表 以$1 $2 … $n 的形式输出所有参数 $1 # 表示第一个参数$2表示第二个参数$n表示第n个参数
- $ 和 $* 的区别 当他们不被 包含时他们之间没有任何区别都是将所有参数当成一份数据彼此之间用空格分隔 当它们都被 包含时区别如下 - $*会将所有的参数从整体上看做一份数据而不是把每个参数都看做一份数据 - $仍然将每个参数都看作一份数据彼此之间是独立的
### set命令
Linux set命令用于设置shell的执行方式可根据不同需要来做设置
以下只列举常用的几个具体百度
shell set -e # 若指令执行结果不为0立即结束shell set -f # 取消使用通配符 set -t # 执行完随后的指令立即退出shell set -v # 显示shell所读取的输入值
### 变量字符串
shell # 变量声明 # 直接赋值 NAMEproj-name # 通过命令替换赋值 CUR_DIR$(cd $(dirname $0); pwd) # $()用来命令替换$0表示当前shell脚本的文件名 # 变量使用通过变量给变量赋值 OUTPUT_DIR$CUR_DIR/output # 变量替换$var和${var}本质上相同但后者会精确变量名的范围 Ahello A_1$AB # A_1值为空因为没有名字为AB的变量 A_2${A}B # A_2值为helloB
# 获取字符串长度 echo ${#A}
# 提取子字符串 echo ${A:0:2} # 输出 he
### 运算符
shell # 关系运算符 -eq(相等) -ne(不等) -gt(大于) -lt(小于) -ge(大于等于) -le(小于等于) if [ $a -eq $b ]; then echo $a fi # 逻辑运算符 ! || if [ !$a $b ]
# 字符串运算符 # 检测两个字符串是否相等 if [ $a $b ] # ! 检测两个字符串是否不相等 if [ $a ! $b ] # -z 检测字符串长度是否为0 if [ -z $a ] # -n 检测字符串长度是否不为0 if [ -n $a ] # $ 检测字符串长度是否为空 if [ $a ] # 文件测试运算符 file/var/test.sh if [ -r $file ] # -b 检测是否为块设备文件 # -c 检测是否为字符设备文件 # -d 检测是否为目录 # -f 检测是否为普通文件 # -g 检测是否设置了SGID位 # -k 检测是否设置了粘着位(Sticky Bit) # -p 检测是否为有名管道 # -u 检测是否设置了SUID位 # -r 检测是否可读 # -w 检测是否可写 # -x 检测是否可执行 # -s 检测是否为空 # -e 检测是否存在 # -S 检测是否为socket
### 流程控制
shell # 退出shell exit 0
### 文件包含
shell脚本可以包含外部的脚本包含后可以使用被包含脚本的函数和变量
shell # 用 . 的方式包含外部脚本 . ./test.sh # 用source的方式包含外部脚本 source ./test.sh
### 参数解析
shell # 调用脚本传入参数 ./test.sh -a aarch64 -b dev -t release -v 2.0.1 # test.sh文件中的参数解析 arch; branch; type; version; date; command; while getopts :a:b:c:d:t:v: opt do case $opt in a) arch$OPTARG ;; b) branch$OPTARG ;; c) command$OPTARG ;; d) date$OPTARG ;; t) type$OPTARG ;; v) version$OPTARG ;; ?) echo Unknown Parameters.; exit 1; ;; esac done
# 四、UML类图
### 图
类图、接口图
##### 类图 类图通常分为三层。 第一层表示**类的名称**如果是抽象类用斜体表示 第二层表示**类的特性**通常就是**字段和属性** 第三层表示**类的操作**通常就是**方法或行为** 前面符号的含义 public - private # protected
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-O0dopQRr-1693297720274)(D:\work\zhounixing\note\resource\个人学习\UML类图 - 类图.png)]
##### 接口图
接口图和类图的区别是顶端有interface显示。 接口图通常分为两层。 第一层表示**接口名称** 第二层表示**接口方法**
此外接口还有另外一种表示方法俗称棒棒糖表示法。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pjw2g0SW-1693297720275)(D:\work\zhounixing\note\resource\个人学习\UML类图 - 接口图.png)]
### UML六种关系
UML分别有以下六种关系实现、泛化、组合、聚合、关联、依赖。
关系紧密程度组合 聚合 关联 依赖 泛化 实现
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Sw4k93Wv-1693297720275)(D:\work\zhounixing\note\resource\个人学习\UML类图 - 关系图.png)]
##### 实现
表示**类与接口之间的关系**指类实现了该接口。
用 **虚线 空心三角形** 表示。
##### 泛化
表示**类与类之间的关系**指类之间的父子关系一个类继承了另一个类。
用 **实线 空心三角形** 表示。
##### 组合 聚合 组合与聚合都是表示**部分与整体的关系**它们的区别如下 聚合 表示一种弱的拥有关系即A对象可以包含B但B不是A的一部分可以脱离A而存在。 例子雁群A与大雁B雁群可以包含大雁但大雁不是雁群的一部分它脱离雁群也能存在。 表示方法**空心菱形 实线箭头** 组合 表示一种强的拥有关系即A对象的组成结构中包含BA和B的生命周期一样。 例子大雁A与翅膀B就是组合关系。 表示方法**实心菱形 实线箭头**
##### 关联
表示**类与类之间的关系**指A类中拥有B类。
* 例子企鹅A类需要知道天气B类情况所以A类中包含B类。 * 表示方法用 **实线箭头** 来表示。
##### 依赖
表示**类与类之间的关系**指A类的方法依赖B类。
* 例子动物A类在活动方法时需要氧气和水B类这样就形成了依赖关系。 * 表示方法用 **虚线箭头** 来表示。
# 五、设计模式
### 六大设计原则 单一原则SRP 一个类只专注于做一件事应该有且仅有一个原因引起类的变更。即高内聚低耦合。 里氏替换原则LSP 所有引用父类的地方必须能透明地使用其子类的对象。属于代码规范 子类必须完全实现父类的抽象方法但不得重写父类的非抽象方法。 子类中可以增加自己的特有方法。 子类可以重载父类方法但不能覆盖。 子类实现抽象方法时返回值可以是父类返回值的子类。 依赖倒置原则DIP 定义 高层模块不应该依赖底层模块两者都应该依赖其抽象 抽象不应该依赖细节 细节应该依赖抽象。 具体实现 模块间的依赖通过抽象发生实现类之间不发生直接的依赖关系依赖关系是通过接口或抽象列产生 接口或抽象类不依赖于实现类 实现类依赖接口或抽象类。 接口隔离原则ISP 只给客户端提供其需要的接口把不需要的剔除掉。 迪米特原则 一个对象应该对其他对象有最少的了解。 你的内部是如何实现和我没关系我只需要知道你提供的public内容其他的一概不关心。 开闭原则OCP 对拓展开放对修改关闭。 重要性 开闭原则是最基础的一个原则前面介绍的所有原则都是开闭原则的具体形态而开闭原则才是其底层逻辑。
### 创建型模式
### 结构型模式
##### 装饰模式 场景 当系统需要新功能的时候是向旧的类中添加新的代码。这些新加的代码通常装饰了原有类的核心职责或主要行为从而增加了主类的复杂度装饰模式提供了一个非常好的解决方案。它把每个要装饰的功能放在单独的类中并让这个类包装它所要装饰的对象。 概念 动态地给一个对象添加一些额外的职责。就增加功能来说Decorator模式相比生成子类更为灵活。 模式解析 1. 装饰模式利用SetComponent来对对象进行包装这样每个装饰对象的实现就和如何使用这个对象分离开了每个装饰对象只关心自己的功能不需要关心如何被添加到对象链当中。 2. UML类图解析 Component 定义一个对象接口可以给这些对象动态地添加职责。 ConcreteComponent 定义了一个具体的对象也可以给这个对象添加一些职责。 Decorator装饰抽象类 继承了Component从外类来拓展Component类的功能。但对于Component来说是无需知道Decorator的存在的。 ConcreteDecorator装饰对象类 定义了具体的装饰类起到给Component添加职责的功能。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YrwtABnS-1693297720275)(D:\work\zhounixing\note\resource\个人学习\设计模式 - 装饰模式.png)]
优点
- 把类中的装饰功能从类中搬移去除简化了原有的类 - 有效地把类的核心职责和装饰功能区分开了而且可以去除相关类中重复的逻辑
### 行为模式
##### 策略模式 场景 在可能遇到多种不同算法或者策略的情形根据实际业务逻辑来变化使用的算法这时可以根据上下文来决定使用哪种算法。 概念 策略模式就是一种定义了一系列的算法将每个算法封装起来并可以相互替换。策略模式让算法独立于它的客户而变化策略模式是一种**对象行为型模式**。 模式解析 1. 策略模式是对算法的封装把算法的责任和算法本身分开委派给不同的对象管理。 2. 策略模式中由客户端决定在什么情况下使用什么策略。 3. 策略模式仅仅封装算法提供新算法到系统中以及老算法从系统中“退休”。 UML类图解析 Context环境类 环境类是使用算法的角色。在环境类中维持一个对抽象策略类的引用实例用于定义所采用的策略。 Strategy抽象策略类 为所有支持的算法声明了抽象方法是所有策略类的父类它可以是抽象类或具体类也可以是接口。环境类通过抽象策略类中声明的方法在运行时调用具体策略类中实现的算法。 StrategyA具体策略类 实现了抽象策略中声明的算法在运行时具体策略类将覆盖在环境类中定义的抽象策略类的对象。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5AIp954Q-1693297720276)(D:\work\zhounixing\note\resource\个人学习\设计模式 - 策略模式.png)]
优点
* 完美支持“开闭原则”用户可以在不修改原有系统的基础上选择算法或策略 也可以灵活地增加或删除。 * 提供了管理算法族的办法易于管理且可避免重复代码。 * 使用策略者模式可以避免多重条件选择语句多重条件选择语句是硬编码不易维护。
缺点
* 客户端必须知道所有的策略类并自行决定使用哪一个策略类。所以策略模式只适用于客户端知道所有的算法或行为的情况同时也加重了客户端的使用难度。 * 策略模式将造成系统产生很多具体策略类任何消息的变化都会导致系统增加一个新的具体策略类。 * 无法同时在客户端使用多个具体策略类 模式对比 策略模式和状态模式的类图相似。
# 六、锁
### 基础锁 -- 互斥锁、自旋锁
互斥锁和自旋锁是最底层的两种锁很多高级的锁都是基于他们实现的可以认为是各种锁的地基。
比如读写锁既可以选择用互斥锁实现也可以用自旋锁实现。
##### 区别
* 互斥锁加锁失败后线程会释放CPU给其他线程发生线程切换 * 自旋锁加锁失败后线程会忙等直到它拿到锁忙等
##### 互斥锁
互斥锁是一种**独占锁**比如当A线程加锁成功后只要线程A没有释放锁线程B加锁就会失败于是会释放CPU给其他线程最终线程B由于一直加锁失败释放CPU最终被阻塞。
**对于互斥锁加锁失败而阻塞的现象是由操作系统内核实现的**。当加锁失败时内核会将线程置为**睡眠状态**等锁被释放后内核会在合适的时间唤醒线程当这个线程成功获取到锁后继续执行。
所以互斥锁加锁失败时会**从用户态陷入到内核态**让内核帮我们切换线程虽然**简化了锁的难度但是存在一定的性能开销成本**在加锁失败和锁被释放时分别会有一次上下文切换如果代码执行的时间很短可能上下文切换的时间都比锁住的代码执行时间还长。
所以**如果能确定被锁住的代码执行时间很短就不应该用互斥锁而选择自旋锁**。
##### 自旋锁
自旋锁是通过CPU提供的CAS函数Compare And Swap在**用户态**完成加锁和解锁的操作不会主动产生上下文切换所以相比互斥锁来说会快一些开销也小一些。
加锁过程
* 查看锁状态如果锁是空闲的执行第二步 * 将锁设置为当前线程持有
CAS函数把这两个步骤合并成一条硬件级指令形成**原子指令**这样保证了这两个步骤的原子性。
自旋锁是比较简单的一种锁一直自旋利用CPU周期直到锁可用。需要注意在单核CPU上需要抢占式的调度器即不断通过时钟中断一个线程运行其他线程否则自旋锁在单核CPU上无法使用因为自旋的线程永远不会释放CPU。
### 读写锁
读写锁由读锁和写锁构成只读取共享资源用读锁共享锁修改共享资源用写锁独占锁。
使用场景能明确区分读操作和写操作的场景。
##### 读优先锁写优先锁 介绍 读优先锁当读线程 A 先持有了读锁写线程 B 在获取写锁的时候会被阻塞并且在阻塞过程中后续来的读线程 C 仍然可以成功获取读锁最后直到读线程 A 和 C 释放读锁后写线程 B 才可以成功获取读锁。 写优先锁当读线程 A 先持有了读锁写线程 B 在获取写锁的时候会被阻塞并且在阻塞过程中后续来的读线程 C 获取读锁时会失败于是读线程 C 将被阻塞在获取读锁的操作这样只要读线程 A 释放读锁后写线程 B 就可以成功获取读锁。 缺点 不管是优先读锁还是优先写锁都有可能出现把非优先的一方饿死的情况为了解决这个问题可以搞个**公平读写锁**不偏袒任何一方。
##### 公平读写锁 介绍 用队列把获取锁的线程排队不管是写线程还是读线程都按照先进先出的原则加锁即可这样读线程仍然可以并发也不会出现饿死的现象。
### 乐观锁悲观锁
前面提到的互斥锁、自旋锁、读写锁都属于悲观锁。 悲观锁 悲观锁做事比较悲观它认为多线程同时修改共享资源的概率比较高很容易出现冲突所以访问共享资源前先要上锁。相反如果多线程同时修改共享资源的概率比较低可以采用乐观锁 乐观锁 乐观锁做事比较乐观它假定冲突的概率很低它的工作方式是先修改完共享资源再验证这段时间有没有发生冲突如果没有其他线程在修改资源那么操作完成如果发现有其他线程已经修改过资源就放弃本次操作。 其实乐观锁全程并没有加锁所以它也叫**无锁编程**。 在线文档编辑、git、svn等都使用了乐观锁。
乐观锁虽然去除了加锁解锁的操作但是一旦发生冲突重试的成本非常高所以**只有在冲突概率非常低且加锁成本非常高的场景下才考虑使用乐观锁**。
# 七、代码坏味道
### 坏味道概述 直观 一眼过去就可以看到的问题比如 * 魔鬼数字 * 函数/类过长 * 圈复杂度高 * 函数/变量命名不规范等 建议规范性的问题尽量通过工具去扫描 微观 需要仔细检查才能发现的问题比如 * 类字段定义不合理 * 函数功能不单一 * 变量作用域过长等 建议代码局部层面问题重点排查优先关注 宏观 代码架构上的整体的问题比如 * 类职责不单一 * 上帝类 * 分层不清楚 * 上下文混乱等 建议需求本身设计类定义类结构关键设计问题这些问题需要结合业务和架构发展
### 设计原则 - 简单设计四个基本原则
* 通过所有测试软件系统对外部需求被正确的完成包括功能性需求和非功能性需求并通过客户验收的标准 * 尽可能消除重复让软件走向高内聚低耦合达到良好正交性的过程并不是所有的重复都可以消除这条原则被描述为最小化重复而不是消除重复 * 尽可能清晰表达漂亮的代码如同优美的散文从不隐藏设计者的意图恰如其分的抽象直截了当的控制代码被阅读的次数远远大于其修改的次数 * 更少的代码元素尽可能降低设计的复杂度保持简单
### 坏味道
##### 重复代码 现象 在多个地点上看到同样的程序结构 解决方法 * 提炼函数 * 函数上移两个互为兄弟的子类中有重复代码提取公共函数到父类中 * 塑造模板函数部分代码相似细节不同。先提取函数再制造模板方法模式把差异部分交给子类实现 * 提炼类两个毫不相关的类出现重复提取到一个类中
##### 过长函数 现象 函数体过长复杂度高难理解后续修改容易引入问题 解决办法 * 提炼函数将重复代码放到一个函数中并让函数名清晰的解释函数的用途 * 以查询取代临时变量程序中将表达式结果放到临时变量中可以将这个表达式提炼到一个独立函数中调用这个新函数去替换这个临时表达式这个新函数就可以被其他函数调用 * 引入参数对象将参数封装到一个对象中以一个对象取代这些参数 * 分解条件表达式将if else等语句的条件表达式提炼出来放到独立的函数中去 * 保持对象完整从某个对象里取出若干值将其作为某次函数调用时的参数由原来传递参数改为传递整个对象 * 以函数对象取代函数大型函数中有许多参数和临时变量将函数放到一个单独对象中局部变量和参数就变成了对象内的字段然后可以在同一个对象中将这个大型函数分解为许多小函数
##### 过多的注释 现象 一段代码有长长的注释然后发现这些注释之所以存在是因为代码很糟糕 解决方法 注释应该是解释why而不是how和what代码告诉你how而注释告诉你why 你感觉需要撰写注释请先尝试重构试着让所有注释都变得多余 * 提炼函数 * 重命名函数
##### 夸夸其谈未来性 现象 过度关注未来可能的变化增加了不必要的东西 * 在理解需求时主观的认为需求变动非常大在设计过程中出现过度的设计 * 追求设计模式的使用经常对程序不必要的地方进行设计模式的使用导致代码不易理解 * 程序的设计过程中封装变化混乱没有将封装变化进行到底。最后过滤考虑了程序的未来性但这些未来性并不明确 解决办法 * 如果某个抽象类其实没有太大的作用请运用折叠继承关系 * 非不要的委派delegation可与用inline class除掉 * 如果函数的某些参数未被用上可删除 * 如果函数名称带有多余的抽象意味可修改函数名让它现实一些
##### 过大的类 现象 一个类过于臃肿出现太多实例变量。容易产生重复代码维护困难代码复用性变差 解决办法 * 提炼类建立一个新类将相关的函数和字段从旧类搬移到新类 * 提炼子类一个类中的某些特性只能被一部分实例使用到可以新建一个子类将只能由一部分实例用到的特性转移到子类中 * 提炼接口两个类中的接口有相同的部分此时可以将相同的子集提炼到一个独立接口中 * 复制被监视数据
##### 冗余类 现象 某个类原本对得起自身的价值但重构使它身形缩水不再做那么多工作或开发者事前规划了某些变化并添加一个类来应付这些变化但变化实际没有发生 解决办法 * 折叠继承关系某个子类并未带来该有的价值因此需要把类折叠起来 * 将类内联化如果一个类不再承担足够责任、不再有单独存在的理由就用内联将其塞进去
##### 过长参数列表 现象 函数有太多的参数常常同时存在过长函数、数据泥团、基本类型偏执等其他坏味道 解决办法 * 一个参数可通过另一个参数查到时可使用“以查询取代参数” * 多个参数属于同一个数据结构时可传入数据结构的对象以保持对象完整 * 多个参数有关联总是同时使用可以引入参数对象 * 某个参数是空标记用于区分函数行为可移除标记参数 * 多个函数有相同的参数实际上是围绕这些参数工作可以将多个函数组合成类
##### 发散式变化 现象 某个class经常因为不同的原因在不同的方向上变化 解决办法 * 提炼类建立一个新类将相关的函数和字段从旧类搬移到新类
##### 霰弹式修改 现象 如果每遇到某种变化都必须在许多不同的classes内做小修改。需要修改的代码散布四处不但很难找到它们也很容易忘记某个重要的修改 解决办法 主要思路是将功能集中到一起常用到以下手段 * 搬移函数、搬移字段、搬移语句到函数等搬移特性的重构手法 * 如果本身架构层次上不应该分开可使用内联函数、内联类、移除子类等手法将模块合并到一起
##### 依恋情节 现象 函数对某个class的兴趣高过对自己所处host class的兴趣。 解决办法 * 搬移函数在该函数最长引用的class中建立一个有着类似行为的新函数。将旧函数变成一个单纯的委托函数或是将就函数完全移除。 * 提炼函数
##### 数据泥团 现象 两个类中的相同值域、或许多函数签名中的相同参数。这些总绑在一起出现的数据真应该放进属于他们自己的对象中。 解决办法 * 提炼类建立一个新类将相关的函数和字段从旧类搬移到新类 * 引入参数对象将参数封装到一个对象中以一个对象取代这些参数 * 保持对象完整从某个对象取出若干值将其作为某次函数调用是的参数由原本传递参数改为传递整个对象
##### 基本类型偏执 现象 使用大量基本数据类型而不是将数据定义成数据结构 解决办法 * 以对象取代数据值将数据值变成对象 * 以类取代型别码如果带着一个有意义的符号名type code的可读性还是不错的。问题在于符号名终究只是个别名编译器看见的、进行型别校验的还是背后那个数值 * 以子类取代型别码它把“对不同行为的了解”从class用户那儿转移到了class自身。如果需要再加入新的行为变化我这是需要添加subclass就行了。如果没有多态机制就必须找到所有条件式并逐一修改它们
##### switch惊悚现身 现象 switch语句是根据类型码进行的多分支选择语句写出短小的switch语句很难即便只有两种条件的switch语句也比我们想要的单个代码块或函数大得多。 解决办法 如果是面向对象语言大多数情况可以用多态替换 * 提取函数将switch语句提取到一个函数中 * 搬移函数将它移到需要多态性的类中 * 通过 子类/状态/策略 中的一种取代类型码 * 最后以多态取代条件表达式 如果是面向过程语言 * 如果case分支超过5个为了使代码看起来更简洁考虑用表驱动的方式 * 如果可以预见类型码会不断新增考虑采用策略模式将控制和处理分离可以提高扩展性符合开闭原则
##### 平行继承关系 现象 当为某个class增加一个subclass必须也为另一个class增加一个subclass。如果发现某个继承体系的名称前缀和另一个继承体系的名称前缀完全相同那么就是平行继承关系 解决办法 让一个继承体系的实例引用另一个继承体系的实例。如果再接再厉运用搬移函数和搬移字段就可以将引用端的继承体系消弭于无形
##### 令人迷惑的临时字段 现象 有时你会看到这样的对象其内某个变量仅为某种特定场景而设或者只在该对象某一段声明周期内生效 解决办法 提炼类把这些变量和其相关函数提炼到一个独立class中提炼后的新对象将是一个method object
##### 过度耦合的消息链 现象 如果你看到用户向一个对象请求另一个对象然后再向后者请求另一个对象然后在请求另一个对象......这就是消息链 解决办法 * 隐藏委托关系 * 提炼函数观察消息链最终得到的对象是用来干什么的可以的话将使用该对象的代码提炼到一个独立函数中
##### 中间人 现象 某个类接口有一半的函数都委托给其他类这样就是过度运用。 解决办法 * 移除中间人直接跟真正负责的对象打交道 * 将函数内联化如果这样的函数只有少数几个可以用内联把他们放进调用端 * 以继承取代委托如果这些中间人还有其他行为可以用继承取代委托把它变成实责对象的子类
##### 狎昵关系 现象 有时你会看到两个类过于亲密花费太多时间去探究彼此的私有数据 解决办法 * 搬移函数、搬移字段帮他们划清界限减少狎昵行径 * 将双向关联改为单向 * 提炼类把两者共同点提炼到一个新的类
##### 异曲同工的类 现象 两个函数做同一件事却有着不同的签名 解决办法 * 重命名函数根据他们的用途重新命名 * 搬移函数将某些行为植入类直到两者的协议一致为止
##### 不完美的库类 现象 库构造得不够好不能让我们修改其中的类使它完成我们希望完成的工作 解决办法
##### 纯稚的数据类 现象 Data Class是指它们拥有一些字段以及用于访问这些字段的函数除此之外一无长处 解决办法 * 封装字段类的数据如果有public字段将其封装 * 封装集合类中如果有容器类的字段将其封装 * 移除setting函数对于不该被其他类修改的字段移除设置函数
##### 被拒绝的遗赠 现象 继承某个类的子类并不需要父类的某些函数、数据或不需要实现父类实现的接口 解决办法 * 下移方法、下移字段让子类拥有只有子类需要的方法或字段 * 以委托代替继承如果子类复用了父类的方法却不愿意支持父类的接口考虑用此方法
# 八、编译相关
先由cmake工具输出标准的构建文件makefile或project文件然后再由make构建出最终的执行文件。
### CMAKE
##### 简介
CMake是一个跨平台的安装编译工具可以用简单的语句来描述所有平台的安装(编译过程)。他能够输出各种各样的makefile或者project文件能测试编译器所支持的C特性,类似UNIX下的automake。
CMake 的组态文件取名为 CMakeLists.txt所有语句都写在这里面当CMakeLists.txt文件确定后直接使用cmake命令运行就能得到输出文件。
Cmake 并不直接建构出最终的软件而是产生标准的建构文件如 Unix 的 Makefile 或 Windows Visual C 的 projects/workspaces然后再按照一般的建构方式使用。
##### 执行流程
shell # 1. 用于配置编译选项一般不需要配置但如果第2步出现错误就需要执行此步 $ ccmake dirName # 2. 根据CMakeLists.txt生成Makefile一般跳过第1步直接执行此步 $ cmake dirName # 3. 执行Makefile文件编译程序生成可执行文件 $ make
##### CMakeLists.txt
### MAKE
### 编译so
shell # 将test.c编译成libtest.so gcc -fPIC -shared test.c -o libtest.so
# 九、Git相关
### 基本概念
- workspace工作区就是电脑能看到的目录 - stage area暂存区/缓存区.git目录下的index文件中 - local repository版本库/本地仓库.git目录 - remote repository远程仓库 - HEAD一个指向当前工作中的本地分支的指针可以当做当前分支的别名
### 仓库操作
shell # 初始化仓库 git init
# 克隆仓库到本地 # 通用 git clone ssh://gitisource-nj.huawei.com:2222/Gauss/gmdb-kvlite.git # 克隆指定分支 git clone -b branchName url
### 提交、修改
shell # 添加文件到缓存区 # 通用 git add * # 把所有文件加入缓存区根据.gitignore过滤(-u表示只添加有更新的文件) git add . -u
# 提交改动到本地仓 # 通用 git commit # 继续上一次的提交 git commit --amend # 如果上一次已经push过那么这次push要用 git push -f
### 查看状态
shell # 查看改动 git diff
# 查看当前分支状态 # 通用 git status # 查看当前分支状态只看被追踪的文件 git status -uno
### 撤销操作
shell # 放弃文件更改(工作区)撤销修改、撤销文件删除 git checkout -- xxx.cpp
# 回退代码到指定版本 git reset xxxx
# 清除所有未跟踪文件 git clean -dfx .
**git reset**
用于回退版本可以指定退回某一次提交的版本
不止可以回退到之前的版本还可以回到之后的版本(比如有A-B-C三个版本当前从C回退到A版本可以直接从A回到C版本)
参数
- --mixed只保留工作目录的改动将缓存区和本地仓库回退默认 - --soft保留工作目录和缓存区的改动将本地仓库回退 - --hard没有保留将工作区、缓存区和本地仓库都回退 - 注意慎用--hard参数它会删除回退点之前的所有信息
shell # 回退到上一个版本mixed git reset HEAD # 回退所有内容到上一版本 git reset HEAD^ # 回退指定文件的版本到上个版本 git reset HEAD^ filename # 回退到指定版本 git reset --soft 052e # 回退到上上上个版本 git reset --hard HEAD~3 # 将本地的状态回退到和远程一样 git reset --hard origin/master
##### git rm
##### git mv
##### git fetch
用于拉代码fetch merge pull
shell # 拉取远程仓origin的master分支 git fetch origin master
##### git remote
用于操作远程仓库
shell # 显示所有远程仓库-v显示出详细信息 git remote -v # 显示指定远程仓库的信息 git remote show url # 添加远程仓库reponame是本地的仓库 git remote add reponame url # 删除远程仓库 git remote rm reponame # 修改仓库名 git remote rename old_name new_name
##### git rebase
shell # cherry-pick两个commit点 git cherry-pick xxx1 git cherry-pick xxx2 # rebase到cherry-pick之前的commit点 git rebase -i xxx0 # 之后进入到第一个修改git文件页面将不需要的commit点标题前面的pick改为s # 然后进入到第二个修改git文件页面将不需要的commit点的标题删掉保留一个即可 # 推到远程仓 git push -f nixing dev_V5R3_RD:dev_V5R3_RD
### 日志操作
##### git log
##### git reflog
### 设置命令
shell # 设置大小写敏感 git config --global core.ignorecase false
### 分支操作
shell # 查看所有分支 git branch -a # 查看当前分支 git branch # 切换分支 git checkout branchName # 删除分支 git branch -d branchName # 强制删除分支 git branch -D branchName
### 标签说明
| 标签名 | 说明 | | :------: | :---------------------------------------: | | feature | 新功能(feature)开发 | | fix | bug修复 | | refactor | 重构代码、优化配置参数、优化逻辑及功能 | | test | 添加单元测试用例相关 | | docs | 添加文档/注释等 | | style | 不修改业务逻辑下仅做代码规范的格式化 | | chore | 构建脚本变动 | | release | 发布版本用于开发分支到release分支的同步 |
### git mm
基本工作流程(需安装git mm)
shell # 1. 初始化git仓 git mm init -u ssh://gitsource.huawei.com:2222/DCP_Industry_ServiceRouter/manifest.git -b br_V8R21C00_main_c30001215_B271_gmdb # 2. 同步代码 git mm sync build fullcode/cmake fullcode/manifest fullcode/router_base # 3. start git mm start br_V8R21C00_main_c30001215_B271_gmdb # 4. 修改文件后先 git add 和 git commit然后 git mm upload
# 十、单位转换
### 时间转换
| 秒s | 毫秒ms | 微秒us | 纳秒ns | | :-----: | :--------: | :--------: | :--------: | | 1 | 1000 | 1000000 | 1000000000 | | -- | 1 | 1000 | 1000000 | | -- | -- | 1 | 1000 |
### 存储转换
| MB | KB | B | bit | | :--: | :--: | :---------: | :-------------: | | 1 | 1024 | 1024 * 1024 | 1024 * 1024 * 8 |