概述
设计模式六大原则
- 单一职责原则:一个类只负责一个功能领域中的相应职责
- 开闭原则:一个软件实体应当对扩展开放,对修改关闭。即软件实体应尽量在不修改原有代码的情况下进行扩展
- 里氏代换原则:所有引用基类(父类)的地方必须能透明地使用其子类的对象
- 依赖倒置原则:高层模块不应该依赖低层模块,两者都应该依赖其抽象;抽象不应该依赖细节,细节应该依赖抽象,其核心思想是:要面向接口编程,不要面向实现编程。
- 接口隔离原则:使用多个专门的接口,而不使用单一的总接口,即客户端不应该依赖那些它不需要的接口。
- 迪米特法则:一个软件实体应当尽可能少地与其他实体发生相互作用
记录一下几种常用数设计模式。
1. 单例模式
1.1 定义和特点
定义:所谓单例,就是整个程序有且仅有一个实例。
特点:
- 类构造器私有
- 持有自己类型的属性
- 对外提供获取实例的静态方法
1.2 优缺点
优点:
- 提供了对唯一实例的受控访问;
- 节省系统资源。由于系统中内存只存在一个对象,因此可以节约资源的资源,对于一些繁琐的创建和销毁的对象,单例模式无意中可以提高系统的性能;
- 单例模式允许可变的数目的实例,使用单利模式进行扩展,使用控制单利对象相似的方法可以获取指定个数的实例,及解决了单利对象共享过多,而有损性能的问题。
缺点:
- 由于单例模式不是抽象的,所有可扩展性比较差。
- 单例类,职责过重,在一定程度上违背了单一职责原则
- 滥用单例将带来一些负面问题,如为了节省资源将数据库连接池对象设计为的单例类,可能会导致共享连接池对象的程序过多而出现连接池溢出;如果实例化的对象长时间不被利用,系统会认为是垃圾而被回收,这将导致对象状态的丢失。
1.3 饿汉式
public class Singleton {
// 1.在类的内部创建自行实例,持有自己类型的属性
private static Singleton instance = new Singleton();
// 2.将构造函数私有化,不可以通过new的方式来创建对象
private Singleton (){}
// 3.提供获取唯一实例的静态方法
public static Singleton getInstance() {
return instance;
}
}
一上来就创建对象,线程安全,比较常用,但是容易产生垃圾,因为如果该实例从始至终都没被使用过,则会造成内存浪费
1.4 懒汉式
public class Singleton {
//持有自己类型的属性,先不创建对象,用到时再创建
private static Singleton instance;
//构造器私有化
private Singleton (){}
//对外提供获取实例的静态方法(多线程环境下加锁)
public static synchronized Singleton getInstance() {
// 用到时如果这个对象引用为null,我们就创建并返回出去
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
线程不安全,使用synchronized加锁;但是直接在方法上加锁的方式其实不够好,在多线程环境下性能会比较低,下面是双重检测机制(DCL)懒汉式
1.5 双重检测机制(DCL)懒汉式
public class Singleton {
private volatile static Singleton singleton; // volatile实现内存可见性
private Singleton (){}
public static Singleton getSingleton() {
if (singleton == null) { //此处判断是为了提高性能
synchronized (Singleton.class) { //同步代码块进行线程加锁
if (singleton == null) {
singleton = new Singleton();
}
}
}
return singleton;
}
}
双重检查模式,进行了两次的判断,第一次是为了避免不要的实例,第二次是为了进行同步,避免多线程问题。由于singleton singleton = new Singleton()
对象的创建在JVM中可能会进行重排序,在多线程访问下存在风险,使用volatile
修饰signleton
实例变量有效,解决该问题。
1.6 静态内部类懒汉式
public class Singleton {
private Singleton(){
}
public static Singleton getInstance(){
return Inner.instance;
}
private static class Inner {
private static final Singleton instance = new Singleton();
}
}
只有第一次调用getInstance方法时,虚拟机才加载 Inner 并初始化instance ,只有一个线程可以获得对象的初始化锁,其他线程无法进行初始化,保证对象的唯一性。目前此方式是所有单例模式中最推荐的模式,但具体还是根据项目选择。
众所周知,单例模式是创建型模式,都会新建一个实例。那么一个重要的问题就是反序列化。当实例被写入到文件到反序列化成实例时,我们需要重写readResolve
方法,以让实例唯一。
private Object readResolve() throws ObjectStreamException{
return singleton;
}