设计模式的分类:
创建型模式:这些设计模式提供了一种在创建对象的同时隐藏创建逻辑的方式,而不是使用 new 运算符直接实例化对象。这使得程序在判断针对某个给定实例需要创建哪些对象时更加灵活。
工厂模式、抽象工厂模式、单例模式、建造者模式、原型模式
结构型模式:这些模式关注对象之间的组合和关系,旨在解决如何构建灵活且可复用的类和对象结构。
适配器模式、桥接模式、过滤器模式、组合模式、装饰器模式、外观模式、享元模式、代理模式
行为型模式:这些模式关注对象之间的通信和交互,旨在解决对象之间的责任分配和算法的封装。
责任链模式、命令模式、解释器模式、迭代器模式、中介者模式、备忘录模式、观察者模式、状态模式、空对象模式、策略模式、模板模式、访问者模式
单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。主要解决的是频繁创建和销毁全局使用的类实例的问题。
优点:
- 内存中只有一个实例,减少内存开销,尤其是频繁创建和销毁实例时(如管理学院首页页面缓存)。
- 避免资源的多重占用(如写文件操作)。
缺点:
- 没有接口,不能继承。
- 与单一职责原则冲突,一个类应该只关心内部逻辑,而不关心实例化方式。
结构:
单例模式包含以下几个主要角色:
- 单例类:包含单例实例的类,通常将构造函数声明为私有。
- 静态成员变量:用于存储单例实例的静态成员变量。
- 获取实例方法:静态方法,用于获取单例实例。
- 私有构造函数:防止外部直接实例化单例类。
- 线程安全处理:确保在多线程环境下单例实例的创建是安全的。
实现方式:懒汉式、饿汉式、双重锁校验、静态内部类、枚举
懒汉式:懒汉式单例模式是最简单的实现方式,它在第一次被请求时才创建实例。这种方式的特点是简单,但存在线程安全问题。
优点:节省资源,只有在需要时才创建实例
缺点:
- 线程不安全,在多线程环境下,可能会产生多个实例。
- 每次调用
getInstance()
方法时都需要进行同步,可能会影响性能。
适用场景:单线程环境、不考虑资源消耗
public class Singleton {
private static Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
饿汉式:饿汉式单例模式在类加载时就创建实例,因此它是线程安全的。这种实现方式的缺点是不管是否需要,单例对象都会被创建。
优点:
- 线程安全:在类加载时就创建实例,避免了多线程环境下的同步问题。
- 简单:实现简单,易于理解和维护。
缺点:资源浪费:不管是否需要,单例对象都会被创建,可能造成资源浪费。
适用场景:多线程环境;单例对象的创建成本不高,或者需要尽早初始化。
public class Singleton {
private static Singleton instance = new Singleton();
private Singleton() {}
public static Singleton getInstance() {
return instance;
}
}
双重锁校验:双重检查锁定是一种在懒汉式基础上增加线程安全的方法。它首先检查实例是否已经创建,如果未创建,则通过同步代码块创建实例。
优点:
- 节省资源:只有在需要时才创建实例。
- 线程安全:通过双重检查和同步代码块确保单例的唯一性。
缺点:
- 复杂性:实现比前两种方式复杂。
- 存在内存一致性问题:需要使用
volatile
关键字确保内存可见性。
适用场景:多线程环境;需要在需要时才创建实例,同时保证线程安全。
public class Singleton {
private static volatile Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
静态内部类:静态内部类是一种通过Java语言本身的特性实现单例模式的方法。这种方式利用了Java的类加载机制来保证线程安全。
优点:
- 线程安全:利用Java的类加载机制,确保单例的唯一性。
- 延迟加载:只有在第一次调用
getInstance()
方法时才加载静态内部类,从而延迟实例的创建。
缺点:资源消耗:尽管延迟加载,但静态内部类的存在可能会占用一定的内存。
适用场景:多线程环境;需要延迟加载单例对象
public class Singleton {
private Singleton() {}
private static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
}
枚举:使用枚举实现单例模式是一种简单且线程安全的方式。Java语言规范保证每个枚举常量只会被实例化一次。
优点:
- 线程安全:Java语言规范保证枚举常量的唯一性。
- 简单:实现简单,易于理解和维护。
- 自动支持序列化机制:枚举类型是单例的天然实现。
缺点:灵活性较差:枚举类型不支持继承,扩展性较差。
适用场景:需要单例对象的场合,且对扩展性要求不高;需要序列化支持的场合。
public enum Singleton {
INSTANCE;
public void someMethod() {
// 可以在这里添加一些方法
}
}
总结
- 懒汉式适合单线程环境或资源消耗不是主要考虑因素的场景。
- 饿汉式适合多线程环境,且单例对象的创建成本不高或需要尽早初始化的场景。
- 双重检查锁定适合多线程环境,需要在需要时才创建实例,同时保证线程安全的场景。
- 静态内部类适合多线程环境,需要延迟加载单例对象的场景。
- 枚举适合需要单例对象,且对扩展性要求不高的场景,同时支持序列化。