创建时间:

最后修改:


# 一些比较容易搞混的概念

这里记录了一些容易搞混的概念,当然这些概念并不仅仅出现在程序设计中。我会尽量通俗易懂的去解释这些概念,与此同时也会失去一定严谨性。如果有错误或者建议请在下面回复,我会改的。(°□°;)



## 01. 观察者模式与发布订阅模式

发布订阅模式可以理解成是观察者模式的一个扩展,观察者和被观察者之间多出了一层。

**观察者模式**:假如我养了只猫,我想时刻都能知道它的状态。好的,那么很简单,你只需要在家 24 小时盯着它看就好了。此时观察者是你,而被观察者就是这只猫了。

**发布订阅模式**:假如有一天我要出门,这样就不能 24 小时盯着它看了,怎么办?很简单,叫你的朋友来盯着它,在它乱叫的时候(行为),打电话通知你。此时订阅者是你,发布者是那只猫,而你朋友是你们之间的中间人。

---

发布订阅模式的优点:

1. **低耦合**:你可以把看猫的事情交给你朋友,麻麻再也不用担心我因为这只猫不能去搞事情了。
2. **可异步**:你的朋友可能不会把猫的变化第一时间内转达给你,你可能也不能在第一时间给出应对措施。




## 02. 共享锁与排它锁

共享锁又叫读锁,它只能读。排它锁也叫写锁,它既能读也能写。

例如有 2 个人,一个叫共享,一个叫排它。然后我把一些画给了他们。

1. **共享**:这些画是我的,但是我愿意分给更多共享的人去看,但是我不会分给排它,因为他们太自私。
2. **排它**:这些画是我一个人的,任何人都不要妄想从我这里得到它,它是我的个人财产,我甚至可以毁掉它。



## 03. 悲观锁与乐观锁

悲观锁和乐观锁是为保证事务中数据的一致性、隔离性而产生的技术手段。在数据库中,它们的实现是依赖于数据库本身所提供的锁机制来完成的。也就是说它们只是一种设计思想,具体的实现方式可能不太一样。

**悲观锁**:和它的名字一样,非常的悲观,总想着别人会修改它的数据。所以它会给这些数据加上排它锁。

**乐观锁**:非常的乐观,认为别人不会去修改它的数据。但是在提交这个事务的时候,会采用一种方式来检查数据是否被别人改了(比如对比修改次数,也就是版本号)。如果被改了,则不能提交这次事务,就必须回滚。而下一步要做的可能是直接报错,让用户处理,或者是重新尝试。



## 04. 集群、分布式、负载均衡

**集群**:一群机器同时干活。

**分布式**:一群机器同时干不同的活。

**负载均衡**:前面说的都是一群机器怎么干活、干什么活。但是具体每台机器要干多少没人知道。所以这时候就需要负载均衡器了,他用于向集群中的机器平均分配任务。



## 05. 并发与并行

有一种机器,同时只能做一件事。这时有两个任务需要做。

**并发**:使用一台机器轮流去做这两个任务。

**并行**:使用两台机器同时去做这两个任务。

并发强调的是能够处理多个任务,并行强调的是能「同时」处理多个任务。在上面的并行模型中,机器1 做 任务1,机器2 做 任务2,同时进行互不影响。



## 06. 同步与异步、阻塞与非阻塞

同步与异步主要体现于「被调用」方,阻塞与非阻塞体现于「调用」方。

**同步异步**:a 调用 b,看 b 如何将计算结果反馈给 a 方法。

**阻塞非阻塞**:a 调用 b,看 a 是否挂起等待 b 方法返回结果。



## 07. is-a 与 has-a

**is-a**:是 xxx,比如猫是种生物,这意味着猫继承了生物的共同特征。

**has-a**:有 xxx,比如猫能喵喵喵,这意味着猫还拥有了某些特殊的特征。

通俗的总结:前者强调的是 `是什么` ,如继承。而后者强调的是 `有什么` ,如组合。



## 08. 接口与抽象类

**接口**:接口的目的只有一个,那就是约束。接口可以理解成是制定的一系列子类要实现的标准。

**抽象类**:与普通类类似,抽象类只是对类的一种扩展,让类可以支持有抽象方法,而类的实质没有改变。

一个类只能继承一个抽象类,那么这个类可以说是这个抽象类的超集。同时一个类可以实现多个接口,那么可以说这个类是这些接口的集合体(包含的关系)。

所以可以发现,继承的子类和抽象类的关系并没有本质的区别,子类还是这个抽象类,只不过实现可能略有不同。而子类与接口的关系则发生了变化,因为子类是由一个或多个接口堆积而成的。

通俗不严谨的总结成:

1. 子类**是**抽象类(is-a);
2. 子类由一些接口**组成**(has-a)。




## 09. 控制反转与依赖注入

**控制反转**:一种设计思想,是用来解耦的,通俗的说就是把控制权反转了过来。比如在类 A 中需要用到类 B,那这时候会在类 A 中写 `new B()` 的代码。这时候可以说类 A 在控制类 B(的实例化过程)。那么反转过来就是,不让类 A 自己实例化类 B 了,而是让别人事先 new 好后想办法让 A 能够使用,而这时候的 `别人` 可以成为是「容器」。

**依赖注入**:对控制反转的具体实现,上面说了类 B 会由「容器」实例化好想办法让类 A 用上,那么依赖注入就是这个 `办法` 。依赖注入的核心是「注入」,很好理解,在这里就是把类 B 注入到类 A 中,比如把类实例当做函数参数传过去。



## 10. URI 与 URL

**URI**:统一资源标识符,它的核心是「标志」。

**URL**:统一资源定位符,它是 URI 的子集,它的核心是「定位」。

比如 http://example.com/video/yazi.wav 这个链接,URI 只管它叫什么,所以是 `video/yazi.wav` 。而 URL 需要找到它,所以就需要全部的信息了(协议、主机名、路径等),所以 URL 就是这整个地址。



## 11. PHP 中类的 self 与 static

**self**:self 写在哪里,调用到的就是哪个类中的方法。

**static**:你当前用的是哪个类,调用到的就是哪个类中的方法。



## 12. JavaScript 中 for...in 与 for...of 循环

- for...of 是在 ES6 中新加入的语法;
- for...of 只会遍历数组中索引为数字的属性;
- for...in 遍历得到的是键名,for...of 得到的键值;
- for...in 会遍历自身和原型上的可枚举属性,for...of 只会遍历自身属性;
- for...in 可以遍历普通的对象,for...of 只能遍历带有 Iterator 接口的对象,因为它就是利用 Iterator 来实现的。