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


    概述

    设计模式六大原则

    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;
    }
    
  • 相关阅读:
    mysql and与or连用时遇到的坑
    mysql : 使用不等于过滤null的问题
    Bio Nio demo
    线上服务器的cpu使用达到100%了,如何排查、定位和解决该问题?
    二叉查找树、平衡二叉树、B树、B+树、聚集索引、非聚集索引
    java实现折线图统计数据
    递归构造树
    python中获取json数组中的具体数值(调用百度AI返回的json数据)
    python中使用ajax回调函数限制
    python+flask框架——前后端数据传递
  • 原文地址:https://www.cnblogs.com/luler/p/13936685.html
Copyright © 2020-2023  润新知