3.设计模式之一:单例模式【建立型模式】

建立型模式分为如下几种。python

  • 单例(Singleton)模式:某个类只能生成一个实例,该类提供了一个全局访问点供外部获取该实例,其拓展是有限多例模式。
  • 原型(Prototype)模式:将一个对象做为原型,经过对其进行复制而克隆出多个和原型相似的新实例。
  • 工厂方法(FactoryMethod)模式:定义一个用于建立产品的接口,由子类决定生产什么产品。
  • 抽象工厂(AbstractFactory)模式:提供一个建立产品族的接口,其每一个子类能够生产一系列相关的产品。
  • 建造者(Builder)模式:将一个复杂对象分解成多个相对简单的部分,而后根据不一样须要分别建立它们,最后构建成该复杂对象。

以上 5 种建立型模式,除了工厂方法模式属于类建立型模式,其余的所有属于对象建立型模式数据库

定义与特色

单例(Singleton)模式的定义:指一个类只有一个实例,且该类能自行建立这个实例的一种模式。设计模式

例如,Windows 中只能打开一个任务管理器,这样能够避免因打开多个任务管理器窗口而形成内存资源的浪费,或出现各个窗口显示内容的不一致等错误。缓存

在计算机系统中,还有 Windows 的回收站、操做系统中的文件系统、多线程中的线程池、显卡的驱动程序对象、打印机的后台处理服务、应用程序的日志对象、数据库的链接池、网站的计数器、Web 应用的配置对象、应用程序中的对话框、系统中的缓存等经常被设计成单例。安全

单例模式有 3 个特色:网络

  1. 单例类只有一个实例对象;
  2. 该单例对象必须由单例类自行建立;
  3. 单例类对外提供一个访问该单例的全局访问点;

结构与实现

单例模式是设计模式中最简单的模式之一。一般,普通类的构造函数是公有的,外部类能够经过“new 构造函数()”来生成多个实例。多线程

可是,若是将类的构造函数设为私有的,外部类就没法调用该构造函数,也就没法生成多个实例。ide

这时该类自身必须定义一个静态私有实例,并向外提供一个静态的公有函数用于建立或获取该静态私有实例。函数

单例模式的结构

单例模式的实现

Singleton 模式一般有两种实现形式。性能

懒汉式单例

该模式的特色是类加载时没有生成单例,只有当第一次调用 get_instance 方法时才去建立这个单例。

class LazySingleton(object):
    __instance = None

    def __init__(self):
        """ Virtually private constructor. """
        pass

    @staticmethod
    def get_instance():
        """ Static access method. """
        if LazySingleton.__instance == None:
            LazySingleton.__instance = LazySingleton()
        return LazySingleton.__instance

s1 = LazySingleton()
s2 = LazySingleton()
print(s1._LazySingleton__instance, s2._LazySingleton__instance, end='\n')  # 未调用get_instance方法时未建立
print(s1.get_instance(), s2.get_instance(), end='\n')  # 指向同一对象
None None
<__main__.LazySingleton object at 0x0000020A56899FD0> <__main__.LazySingleton object at 0x0000020A56899FD0>

注意:若是编写的是多线程程序,注意存在线程非安全的问题。若是保证线程安全,那么每次访问时都要同步,会影响性能,且消耗更多的资源,这是懒汉式单例的缺点。

饿汉式单例

该模式的特色是类一旦加载就建立一个单例,保证在调用 get_instance 方法以前单例已经存在了

class HungrySingleton(object):
    __instance = None
    def __new__(cls, *args, **kwargs):
        if cls.__instance == None:
            cls.__instance = super(HungrySingleton, cls).__new__(cls)
        return cls.__instance

    @staticmethod
    def get_instance():
        return HungrySingleton.__instance

h1 = HungrySingleton()
h2 = HungrySingleton()
print(h1._HungrySingleton__instance, h2._HungrySingleton__instance, end='\n')  # 未调用get_instance方法时已经建立
print(h1.get_instance(), h2.get_instance(), end='\n')  # 与上面一致
<__main__.HungrySingleton object at 0x0000020A568A1048> <__main__.HungrySingleton object at 0x0000020A568A1048>
<__main__.HungrySingleton object at 0x0000020A568A1048> <__main__.HungrySingleton object at 0x0000020A568A1048>

饿汉式单例在类建立的同时就已经建立好一个静态的对象供系统使用,之后再也不改变,因此是线程安全的,能够直接用于多线程而不会出现问题。

应用实例

【例1】用懒汉式单例模式模拟产生美国当今总统对象。

分析:在每一届任期内,美国的总统只有一人,因此本实例适合用单例模式实现,图所示是用懒汉式单例实现的结构图。

class President(object):
    __instance = None

    def __init__(self):
        print("产生一个新总统")

    @staticmethod
    def get_instance():
        if President.__instance == None:
            President.__instance = President()
        else:
            print("已经有一个总统了")
        return President.__instance

    def get_name(self):
        print("特朗普是新总统")

if __name__ == '__main__':
    p1 = President.get_instance()
    p1.get_name()
    p2 = President.get_instance()
    p2.get_name()
    if p1 == p2:
        print('他们是同一人')
    else:
        print('他们不是同一人')
产生一个新总统
特朗普是新总统
已经有一个总统了
特朗普是新总统
他们是同一人

应用场景

前面分析了单例模式的结构与特色,如下是它一般适用的场景的特色。

  • 在应用场景中,某类只要求生成一个对象的时候,如一个班中的班长、每一个人的身份证号等。
  • 当对象须要被共享的场合。因为单例模式只容许建立一个对象,共享该对象能够节省内存,并加快对象访问速度。如 Web 中的配置对象、数据库的链接池等。
  • 当某类须要频繁实例化,而建立的对象又频繁被销毁的时候,如多线程的线程池、网络链接池等。

单例模式的扩展

单例模式可扩展为有限的多例(Multitcm)模式,这种模式可生成有限个实例并保存在 ArmyList 中,客户须要时可随机获取,其结构图如图所示。

相关文章
相关标签/搜索