创建型概述
- 创建型模式关注"怎么创建对象",特点是"将对象的创建和使用分离",降低系统的耦合度
创建型模式分为:
- 单例模式
- 工厂方法模式
- 抽象工程模式
- 原型模式
- 建造者模式
单例模式
- 该模式只有一个类,并确保只创建一个对象,提供唯一访问对象的方式,可以直接访问,不需要实例化该类对象。
角色
- 单例类: 只能创建一个实例的类
- 访问类:使用单例类
举例
单例设计模式分两类:
- 饿汉式:类加载时创建实例对象 方式1:静态成员变量
/**
* @author :yangzhipeng
* @date : 2023/3/6 14:27
* Description : 单例模式:饿汉式 :静态成员变量
*/
public class Singleton {
/**
* 私有构造方法 确保只有一个对象
*/
private Singleton(){}
/**
* 在本类中创建本类对象
*/
private static Singleton instance = new Singleton();
/**
* 提供一个公共的访问方式,让外界获取该对象
*/
public static Singleton getInstance(){
return instance;
}
}
- 方式2:静态代码块
/**
* 声明Singleton类型的变量
*/
private static Singleton instance;
/**
* 在静态代码快中进行赋值
*/
static{
instance = new Singleton();
}
懒汉式:首次使用该对象时创建对象
方式1:(线程不安全)
/**
* @author :yangzhipeng
* @date : 2023/3/6 14:27
* Description : 单例模式:懒汉式1 :线程不安全
*/
public class Singleton {
/**
* 私有构造方法 确保只有一个对象
*/
private Singleton(){}
/**
* 声明类型
*/
private static Singleton instance;
/**
* 提供一个公共的访问方式,让外界获取该对象
*/
public static Singleton getInstance(){
//判断instance是否为null
//若没有,创建一个 ; 若有,直接返回
if(instance == null){
//线程1等待,线程2执行到这里也会创建
instance = new Singleton();
}
return instance;
}
}
线程安全解决办法:方法上加synchronize同步锁
/**
* 提供一个公共的访问方式,让外界获取该对象
*/
public static synchronized Singleton getInstance(){
//判断instance是否为null
//若没有,创建一个 ; 若有,直接返回
if(instance == null){
//线程1等待,线程2执行到这里也会创建
instance = new Singleton();
}
return instance;
}
方式3:双重检查锁:调整加锁的时机 (推荐使用)
/**
* @author :yangzhipeng
* @date : 2023/3/6 14:27
* Description : 单例模式:懒汉式2 :双重检查锁
*/
public class Singleton {
/**
* 私有构造方法 确保只有一个对象
*/
private Singleton(){}
/**
* 声明类型
*/
private static Singleton instance;
/**
* 提供一个公共的访问方式,让外界获取该对象
* synchronized加锁 使其线程安全
*/
public static Singleton getInstance(){
//判断instance是否为null
//若没有,创建一个 ; 若有,直接返回
if(instance == null){
//抢到锁之后再次判断是否为空
synchronized (Singleton.class){
if(instance == null){
instance = new Singleton();
}
}
}
return instance;
}
}
方法4:静态内部类
JVM在加载外部类的过程中,不会加载静态内部类,内部类的属性/方法被调用时才会加载。被static修饰属性可以保证只实例化一次,并严格保证实例化顺序。
/**
* @author :yangzhipeng
* @date : 2023/3/6 14:27
* Description : 单例模式:懒汉式2 :静态内部类方式
*/
public class Singleton {
/**
* 私有构造方法 确保只有一个对象
*/
private Singleton(){}
/**
* 静态方法创建对象
*/
private static class SingletonHolder{
private static final Singleton INSTANCE = new Singleton();
}
/**
* 对外提供静态方法获取该对象
*/
public static Singleton getInstance(){
return SingletonHolder.INSTANCE;
}
}
静态内部类方式在没有加任何锁的情况下保证了多线程下的安全,并且没有性能影响和空间浪费。比较推荐
极力推荐:饿汉式:枚举方式
/**
* @author :yangzhipeng
* @date : 2023/3/6 14:27
* Description : 单例模式:饿汉式 :枚举方式
*/
public enum Singleton {
INSTANCE;
}
枚举类型是线程安全的,只会装载一次,是所有单例实现中唯一一种不会被破坏的单例实现模式
存在的问题:
1.破坏单例模式(除了枚举方式)
问题的解决:
- 序列化,反序列化方式破坏单例模式解决方法:
在Singleton类中添加readResolve()方法
/**
* @author :yangzhipeng
* @date : 2023/3/6 14:27
* Description : 单例模式:懒汉式2 :静态内部类方式
*/
public class Singleton {
/**
* 私有构造方法 确保只有一个对象
*/
private Singleton(){}
/**
* 静态方法创建对象
*/
private static class SingletonHolder{
private static final Singleton INSTANCE = new Singleton();
}
/**
* 对外提供静态方法获取该对象
*/
public static Singleton getInstance(){
return SingletonHolder.INSTANCE;
}
/**
* 当进行反序列化时,会自动调用该方法,将该方法的返回值直接返回
*/
public Object readResolve(){
return SingletonHolder.INSTANCE;
}
}
- 反射方式破解单例的解决方式
在Singleton中添加静态变量判断是否是第一次创建对象
public class Singleton {
//解决反射破解单例
private static boolean flag = false;
/**
* 私有构造方法 确保只有一个对象
*/
private Singleton(){
//加锁解决多线程
synchronized (Singleton.class){
//flag值为false说明是第一次访问,反之直接抛出异常
if(flag){
throw new RuntimeException("不能创建多个Singleton对象");
}
//将flag设置为true
flag = true;
}
}
/**
* 静态方法创建对象
*/
private static class SingletonHolder{
private static final Singleton INSTANCE = new Singleton();
}
/**
* 对外提供静态方法获取该对象
*/
public static Singleton getInstance(){
return SingletonHolder.INSTANCE;
}
}