当前位置:   article > 正文

【接口平台】设计模式之单例模式_单例模式的接口

单例模式的接口

一、定义

单例模式是一种应用广泛的模型,适用于一个类全局只能有一个实例的情况
比如说,在一个教学系统中定义了一个班长类,但是一个班只能有一个班长。那么需要限定一下,其他类不能随便创建班长对象,只能获取本班的班长。单例模式需要满足以下几个特征:

  • 系统创建,不能由外部随便创建
  • 只能创建一次,不能重复创建
  • 外部只能调用

下面逐个分析如何达到这些特征

  1. 系统创建
    要求构造函数私有化,只有这样外部就无法通过new创建对象,因为new其实就是调用了构造函数
  2. 只能创建一次
    意味着在每次调用实例前都需要判断一下有没有被创建,若创建过了则直接返回已经创建好的实例对象,否则内部自行创建
  3. 外部只能调用
    外部调用要靠公有函数实现,且外部只能通过公有函数接口访问对象,这说明对象应该是一个封装的私有对象

最简单的单例模式实现如下:

public class Singleton {

    private Singleton() { //不可随意创建对象
        System.out.println("创建单例模式: " + this); //测试,创建成功后输出对象哈希码
    }

    //饿汉式,创建后直接分配内存
    private static Singleton instance = new Singleton();

	//获取对象的公有接口
    public static Singleton getInstance() {
        return instance;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

这是最简单的实现,没有考虑空间效率和线程安全

二、考虑空间效率

上面是饿汉式的实现过程,顾名思义,这个类是贪婪的,刚声明就把内存空间开辟后据为己有,不管此时是不是立刻就需要。那么如何让它懒一些,在需要用时再开辟空间呢?实现过程如下:

//懒汉式
private static Singleton instance = null;
public static Singleton getInstance() {
    if(null == instance) instance = new Singleton();
    return instance;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

new Singleton()从声明变量处移到getInstance()函数中,在程序刚开始运行时,创建的只是空指针instance,只有当外界第一次调用getInstance()时才真正的创建。考虑节约空间资源,但是又有一个线程安全的问题

三、考虑线程安全

当创建饿汉式单例模式时并不会遇到这个问题,因为类的初始化是不会发生线程安全问题,但是把对象的初始化放到一个函数中时就可能出现问题
试想,一个线程查看到该对象没有被创建,于是准备着手创建,此时另一个线程也发现该对象没有被创建,都各自创建一遍,此时内存中就存在两个对象。解决这个问题可通过synchronized关键字锁住资源,防止写冲突

//改进后线程安全的双重锁懒汉式
private volatile static Singleton instance = null; //volatile 禁止重排序,所有的写操作将在读操作以前
public static Singleton getInstance() {
    if(null == instance) {
        synchronized (Singleton.class) {
            if(null == instance) instance = new Singleton();
        }
    }
    return instance;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

volatile关键字的使用很有讲究,但这个依然是不安全,于是有了下面这个终极答案:

//内部静态类实现
public static Singleton getInstance() {
    return SingletonHolder.sInstance;
}

private static class SingletonHolder {
    private static final Singleton sInstance = new Singleton();
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

测试代码如下:

public static void main(String[] args) {
       Singleton s1 = Singleton.getInstance();
       System.out.println("创建s1: " + s1.toString());
       Singleton s2 = Singleton.getInstance();
       System.out.println("创建s2: " + s2.toString());
   }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

这里获取了两次实例对象,看看到底是不是同一个。加上私有构造函数中同样打印输出了对象的哈希码,一共需要输出三次

四、python实现

单例模式的代码实现如下

class singleton(object): # 创建一个类
    mysingleton = None
    def __new__(self, *args, **kwargs): #重写__new__方法
        if self.mysingleton is None:
            self.mysingleton = object.__new__(self) #调用用object类的__new__方法创建实例
            return self.mysingleton #返回实例
        else:
            return self.mysingleton#返回实例,与上面的返回相同
  
if __name__ == "__main__":
    a = singleton() #实例化一个a对象
    b = singleton() #实例化一个b对象
    print(id(a))  #id() 函数返回对象的唯一标识符,标识符是一个整数。
    print(id(b))  #如果两个一样就说明是同一个实例化对象
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

五、应用场景

单例模式的使用场景例如:

  • 数据库连接池
  • 日志logger插入
  • 计时器
  • 权限校验
  • 网站计数器
  • windows资源管理器
  • 回收站
  • 线程池等资源池

六、python数据库连接池的使用

import dbconfig
import pymysql

class singleton(object):
    dbconn = None
    def __new__(self, *args, **kwargs):
        dbname=args
        if self.dbconn is None:
            self.dbconn = pymysql.connect(dbconfig.dbDict.get(dbname[0]), dbconfig.dbUser, dbconfig.dbPassword).cursor()
            print("aaa")
            return self.dbconn
        else:
            print("bbb")
            return self.dbconn

if __name__ == "__main__":
    test = singleton("ars1")
    result =test.execute("select id,code from info.property where status=1")
    print(test.fetchall())
    print(id(test))
    test1 = singleton("ars1")
    result1 = test1.execute("select id,code from info.property where status=1")
    print(test1.fetchall())
    print(id(test1))
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/AllinToyou/article/detail/68962
推荐阅读
相关标签
  

闽ICP备14008679号