常用设计模式--单例模式

概述

设计模式六大原则

  1. 单一职责原则:一个类只负责一个功能领域中的相应职责
  2. 开闭原则:一个软件实体应当对扩展开放,对修改关闭。即软件实体应尽量在不修改原有代码的情况下进行扩展
  3. 里氏代换原则:所有引用基类(父类)的地方必须能透明地使用其子类的对象
  4. 依赖倒置原则:高层模块不应该依赖低层模块,两者都应该依赖其抽象;抽象不应该依赖细节,细节应该依赖抽象,其核心思想是:要面向接口编程,不要面向实现编程。
  5. 接口隔离原则:使用多个专门的接口,而不使用单一的总接口,即客户端不应该依赖那些它不需要的接口。
  6. 迪米特法则:一个软件实体应当尽可能少地与其他实体发生相互作用

记录一下几种常用数设计模式。

1. 单例模式

1.1 定义和特点

定义:所谓单例,就是整个程序有且仅有一个实例。

特点:

  • 类构造器私有
  • 持有自己类型的属性
  • 对外提供获取实例的静态方法

1.2 优缺点

优点:

  1. 提供了对唯一实例的受控访问;
  2. 节省系统资源。由于系统中内存只存在一个对象,因此可以节约资源的资源,对于一些繁琐的创建和销毁的对象,单例模式无意中可以提高系统的性能;
  3. 单例模式允许可变的数目的实例,使用单利模式进行扩展,使用控制单利对象相似的方法可以获取指定个数的实例,及解决了单利对象共享过多,而有损性能的问题。

缺点:

  1. 由于单例模式不是抽象的,所有可扩展性比较差。
  2. 单例类,职责过重,在一定程度上违背了单一职责原则
  3. 滥用单例将带来一些负面问题,如为了节省资源将数据库连接池对象设计为的单例类,可能会导致共享连接池对象的程序过多而出现连接池溢出;如果实例化的对象长时间不被利用,系统会认为是垃圾而被回收,这将导致对象状态的丢失。

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;
}
posted @ 2020-11-06 14:25  乐子不痞  阅读(172)  评论(0编辑  收藏  举报
回到顶部