课程使用语言 Java
1. Singleton 单例模式
保证在内存中只有一个实例。
1.1 饿汉式
- 类中定义出来此实例类型变量,并且设置为 私有 静态 和 final 的。(new 出实例。也可以用静态语句块方式定义)
- 类中将构造方法重写为 private 的,且不做任何事情。(其他人 New 不出来)
- 提供 public 方法返回此实例。
利用:JVM 每个 class 只会 load 到内存一次。
优点:简单实用,推荐使用。
缺点:类装载时就实例化了。(后来的懒加载是使用的时候加载,无此缺点。)
1.2 懒汉式
特点:什么时候用时什么时候初始化。
- 先声明一个实例(private static),但不初始化。
- 重写构造方法为 private 的。
- 在 getInstance 中判断实例不存在时初始化,存在则返回。
优点:什么时候用什么时候初始化。
缺点:多线程并发中可能初始化多次。
造成问题测试:多线程中输出实例的哈希值(不同对象的哈希值应该是不同的)。
1.3 加锁
- 判断实例为 null 则加个锁,让线程抢锁(锁的执行是单人次的);若非 null 则返回实例
- 抢到锁后,再次判断这个实例是否被初始化,若有则返回实例,若无则初始化
特点:可以保证并发没问题
缺点:加锁程序变重
1.4 静态内部类
- 在类中定义一个 私有、静态 的类,作为此实例的持有者
- 在静态内部类中初始化此实例为 私有的 成员变量
- 用外层类中公有的方法
getInstance
,返回静态内部类的私有成员变量
利用:jvm 在加载类时只会加载一次;且只在用时加载
特点:实现了懒加载(用时加载)
缺点:无
说明:因为只有 getInstanct
使用了内部类,所以只有调用它时才加载;且 JVM 保证只加载类只加载一次。
1.5 枚举单例
- 定义一个枚举类,只给它一个取值,就是 Instance
特点:不仅可以防并发,还可以防反序列化。
(需要去找下文档看看)
2. 策略模式(Strategy)
就像 Golang 的 sort.Sort()
功能这样的实现。
type SortBy []Type
func (a SortBy) Len() int { return len(a) }
func (a SortBy) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a SortBy) Less(i, j int) bool { return a[i] < a[j] }
11 代理模式
静态代理和动态代理
类似于 继承 和 聚合,想象一下,如果要在 doSomething()
本身上,记录一些事情比如记录此函数的执行时间。那么可以用继承的方法,同样调用父类的 doSomething()
再记录一下别的事情。
代理呢,是另一种方法。这个代理就是代理做某些事情,你把你的方法传过来,我帮你执行,在帮你执行时我也可以做自己的事。
这样的话,就需要你传过来你的类,你的方法,让我(代理)来给你执行。我在代理执行的时候,就可以做自己的一些事。
11.1 静态代理
只代理某 种 类。如下面的 Go 代码,DurationProxy
只能代理 func()
这样的函数,如果是一个 func(in int) error
这样的函数就不能代理了。
func main() {
DurationProxy(Move)
}
func DurationProxy(f func()) {
start := time.Now().Unix()
f()
end := time.Now().Unix()
fmt.Println("this func cost", end-start, "second")
}
func Move() {
time.Sleep(3 * time.Second)
}
11.2 动态代理
代理任何类。
将类、方法、参数都传入代理中,由代理动态反射到原来的对象,然后来执行。
有疑问加站长微信联系(非本文作者)