常用设计模式

六大原则

  • 单一职责原则:一个类中应该是一组相关性很高的函数、数据的封装;
  • 开闭原则:软件中的对象(类、模块、函数等)应该对于扩展事开放的,但是对于修改是封闭的;
  • 里氏替换原则:所有引用基类的地方必须能透明地使用其子类的对象;
  • 依赖倒置原则:模块间的依赖通过抽象发生,实现类之间不发生直接的依赖关系,其依赖关系通过接口或抽象类产生;
  • 接口隔离原则:客户端不应该依赖它不需要的接口,即类间的依赖关系应该建立在最小的接口上;
  • 迪米特原则:一个对象应该对其他对象有最少的了解,即类的内部如何实现与调用者或者依赖者没有关系。

单例模式

确保某一个类只有一个实例,并且自行实例化并向这个系统提供这个实例。实现关键点:

  • 构造函数不对外开放
  • 通过一个静态方法或者枚举返回单例类对象
  • 确保单例类的对象有且只有一个,尤其是在多线程环境下
  • 确保单例类对象在反序列化时不会重新构建对象

饿汉式

1
2
3
4
5
6
7
8
9
public class Singleton {
private static final Singleton INSTANCE = new Singleton();

private Singleton() {}

public static Singleton getInstance() {
return INSTANCE;
}
}
  • 优点:实现简单,多线程安全
  • 缺点:不管有没有使用都会被初始化,浪费资源

懒汉式

1
2
3
4
5
6
7
8
9
10
11
12
public class Singleton {
private static Singleton sInstance = null;

private Singleton() {}

public static synchronized Singleton getInstance() {
if (sInstance == null) {
sInstance = new Singleton();
}
return INSTANCE;
}
}
  • 优点:使用时加载,一定程度上节省了资源
  • 缺点:第一次加载时速度较慢,且每次获取实例都需要进行同步,开销较大

Double Check Lock(DLC)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class Singleton {
private volatile static Singleton sInstance = null;

private Singleton() {}

public static Singleton getInstance() {
//避免不必要的同步
if (sInstance == null) {
synchronized (sInstance) {
//在对象为null时创建实例,确保只会创建一次
if (sInstance == null) {
sInstance = new Singleton();
}
}
}
return INSTANCE;
}
}
  • 优点:资源利用率高,延时实例化
  • 缺点:第一次加载时稍慢

静态内部类方式

1
2
3
4
5
6
7
8
9
10
11
public class Singleton {
private Singleton() {}

public static Singleton getInstance() {
return SingletonHolder.INSTANCE;
}

private static class final SingletonHolder {
private static final Singleton sInstance = new Singleton();
}
}
  • 优点:延时加载、线程安全
  • 缺点:实现较复杂

以上方法在反序列化时会重复创建对象,解决方法为在类中添加以下方法:

1
2
3
private Object readResolve() throws ObjectStreamException {
return sIntance;
}

枚举方式

1
2
3
public enum SingletonEnum {
INSTANCE;
}
  • 优点:延时加载、线程安全、反序列化同样为单例

Builder模式

主要用于将一个复杂对象的构建与它的表示分离