前言
无论是在日常的工作中还是面试中,都必须会涉及到设计模式方面的知识,日常开发中,单例模式,代理模式等会经常使用。面试的时候也会被要求手写一些常用的设计模式。这里在此做个汇总:
《》
作用
- 提高代码维护性,可拓展性
- 提高代码复用率,降低开发成本
- 提高代码可读行,让代码容易让他人理解
设计原则
设计模式遵循以下原则:
- 1.单一职责原则
一个类只有一种情况能引起它的变化,通俗的讲,一个类不要什么乱七八糟的东西都有,它的作用要简单纯粹。 - 2.开闭原则
一个类一旦被引用,就尽量不要去修改原来的东西,可以通过添加拓展来实现想要的效果,更好的热插拔。 - 3.里氏替换原则
是对开闭原则的补充,基类可以实现的行为,它的子类也可以实现。当子类替换掉基类时,既能复用父类,也能在子类上拓展新的行为。 - 4.依赖倒转原则
是开闭原则的基础,日常开发中,要面向接口编程,面向抽象而不是面向具体。在使用具体的实现类时,尽量不与其他的具体实现类交互,而是与具体实现类的上层接口交互。这个在Java开发中十分常见。 - 5.接口隔离原则
如果一个接口,实现类出现了没有具体实现该接口的方法,那么要把接口拆分出来写,反过来讲,即拆分出来的接口中的方法在实现类中要全部实现。 - 6.合成复用原则
要尽量使用合成/聚合,尽量不要使用继承。
单例模式
一个简单的单例有以下3点要素
- 声明当前类的静态私有变量
- 构造方法私有化
- 公有方法返回唯一实例
- 简单懒汉式单例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16public class Singleton {
//1. 声明私有变量 ourInstance(用以记录 Singleton 的唯一实例)
private static Singleton ourInstance = null;
//2. 把类的构造方法私有化,不让外部调用构造方法实例化
private Singleton() {
}
//3. 定义公有方法提供该类的全局唯一访问点
//4. 外部通过调用getInstance()方法来返回唯一的实例
public static Singleton newInstance() {
if( ourInstance == null){//懒汉式
ourInstance = new Singleton();
}
return ourInstance;
}
}
这样即可保证在进程中只有一个实例。
通常情况下单线程用上面的方法是没有问题的,但如果把它放进多线程的环境下,就会出现问题:多线程并发同时调用newInstance()方法,会重复创建实例。对此,需要进行加锁优化。
- 添加同步锁懒汉式单例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15class Singleton{
private static Singleton instance = null;
private Singleton(){}
public static Singleton getInstance(){
// 加入同步锁
synchronized(Singleton.class) {
if (instance == null)
instance = new Singleton();
}
return instance;
}
}
添加了同步锁之后可以避免多线程并发引起的安全问题。
但是,同时加锁之后,每次访问都要进行线程同步,会耗时耗能。
综合上述问题,可采用静态内部类单例。
- 静态内部类懒汉式单例:
在调用newInstance()方法时必须要先实例了Singleton,不能在newInstance中实例Singleton。利用静态内部类来完成调用前的加载。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18class Singleton {
// 1. 创建静态内部类
private static class Singleton2 {
// 在静态内部类里创建单例
private static Singleton ourInstance = new Singleton();
}
// 私有构造函数
private Singleton() {
}
// 延迟加载、按需创建
public static Singleton newInstance() {
return Singleton2.ourInstance;
}
}
- 外部调用类的newInstance()
- 自动调用Singleton2.ourInstance
- 此时单例类Singleton2得到初始化
- 而该类在装载 & 被初始化时,会初始化它的静态域,从而创建单例;
- 由于是静态域,因此只会JVM只会加载1遍,Java虚拟机保证了线程安全性
- 最终只创建1个单例
-饿汉式单例
唯一的区别是:
饿汉式:单例创建时机不可控,即类加载时,自动创建单例
懒汉式:单例创建时机可控,即有需要时,才手动创建单例
饿汉时单例是线程安全,能避免懒汉式因多线程引发的各种问题。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15class Singleton {
// 1. 加载该类时,单例就会自动被创建
private static Singleton ourInstance = new Singleton();
// 2. 构造函数 设置为 私有权限
// 原因:禁止他人创建实例
private Singleton() {
}
// 3. 通过调用静态方法获得创建的单例
public static Singleton newInstance() {
return ourInstance;
}
}
总结
主要介绍了设计模式的基本概念和单例模式,其他设计模式可参看:
设计模式(二):简单工厂与策略模式