专栏首页python3Python设计模式——单例模式

Python设计模式——单例模式

一、单例模式理论

单例模式:
    保证某一个类只有一个实例,而且在全局只有一个访问点
优点:
    1、由于单例模式要求在全局内只有一个实例,因而可以节省比较多的内存空间
    2、全局只有一个接入点,可以更好地进行数据同步控制,避免多重占用
    3、单例可长驻内存,减少系统开销

缺点:
    1、单例模式的扩展是比较困难的
    2、赋予了单例模式太多的职责,某种程度上违反了单一职责原则(六大设计原则之一)
    3、单例模式是并发协作软件模块中需要最先完成的,因而其不利于测试
    4、单例模式在某种情况下会导致资源瓶颈

应用场景:
    1、生成全局唯一的变量,比如序列号
    2、访问全局复用的唯一资源,如磁盘,总线等
    3、单个对象占用的资源太多,如数据库等
    4、系统全局统一管理,如windows下的任务管理器

二、对__new__的分析

# class Demo:
#     def __init__(self, name):
#         self.name = name
#
#     def show_name(self):
#         print("Name is: {}".format(self.name))
#
# if __name__ == '__main__':
#
#     d = Demo("toby")
#     d.show_name()

'''
引用大神的描述:
    这样便是__init__最普通的用法了。但__init__其实不是实例化一个类的时候第一个被调用的方法。
    当使用Demo("toby")这样的表达式来实例化一个类时,最先被调用的方法其实是 __new__ 方法。
    __new__ 方法是什么?
    __new__方法接受的参数虽然也是和__init__一样,但__init__是在类实例创建之后调用,而__new__方法正是创建这个类实例的方法。
'''

class Demo:
    def __new__(cls, name):
        print("Call __new__")
        class_instance = super(Demo, cls).__new__(cls)
        print("new创建了类实例:", class_instance) #打印一下
        return class_instance #返回Demon类的一个实例给__init__,然后利用这个实例来调用类的__init__方法

    def __init__(self, name): #那__init__用什么来接收__new__返回来的类实例呢?答案就是self
        print("init接收到new返回回来的类实例:", self) #打印一下这个self,也就是看一下由__new__产生的实例
        print("Call __init__")
        self.name = name

    def show_name(self):
        print("Name is: {}".format(self.name))
#
# if __name__ == '__main__':
#     d = Demo("toby")
#     d.show_name()

'''
引用大神的总结:
    所以,__init__ 和 __new__ 最主要的区别在于:
    1、__init__ 通常用于初始化一个新实例,控制这个初始化的过程,比如添加一些属性, 
    做一些额外的操作,发生在类实例被创建完以后。它是实例级别的方法。
    2、__new__ 通常用于控制生成一个新实例的过程。它是类级别的方法。
    但是说了这么多,__new__最通常的用法是什么呢,我们什么时候需要__new__?,单例模式就是一个很好的例子
'''

三、单例模式(案例1)

#coding:utf-8
import threading
import time

#这里使用方法__new__来实现单例模式
class Singleton(object): #抽象单例
    def __new__(cls, *args, **kwargs):
        if not hasattr(cls, "_instance"):
            orig = super(Singleton, cls)
            cls._instance = orig.__new__(cls, *args, **kwargs)
        return cls._instance

#总线
class Bus(Singleton):
    lock = threading.RLock()
    def sendData(self, data):
        self.lock.acquire()
        time.sleep(3)
        print("Sending Signal Data...", data)
        self.lock.release()

#线程对象,为更加说明单例的含义,这里讲Bus对象实例化在了run里
class VisitEntity(threading.Thread):
    my_bus = ""
    name = ""
    def getName(self):
        return self.name
    def setName(self, name):
        self.name = name
    def run(self):
        self.my_bus = Bus()
        self.my_bus.sendData(self.name)
if __name__ == '__main__':
    for i in range(3):
        print("Entity {} begin to run...".format(i))
        v = VisitEntity()
        v.setName("Toby"+str(i))
        v.start()

四、单例模式(案例2)

#使用__new__类方法来保证只有一个实例被创建出来
class OneOnly(object):
    _singleton = None
    def __new__(cls, *args, **kwargs):
        if not cls._singleton: #判断是否创建有实例,如果没有则调用super()函数来创建它
            cls._singleton = super(OneOnly, cls).__new__(cls) #构造方法__new__被调用时,会构造该类的一个新实例
        return cls._singleton

#定义一个普通的类,仅有初始化方法__init__
class Test:
    def __init__(self, name):
        self.name = name

#定义一个Demo类,并继承实现单例模式的OneOnly类
class Demo(OneOnly):
    def __init__(self, name):
        self.name = name

    def chage_name(self, new_name):
        self.name = new_name

    def show_name(self):
        print("Name is: {}".format(self.name))

if __name__ == '__main__':

    #当通过OneOnly类中的构造方法构造实例时,总是会的得到完全相同的实例,内存地址也相同
    # o1 = OneOnly()
    # o2 = OneOnly()
    # print(o1)
    # print(o2)

    #通过Test类创建出来的两个实例t1和t2,是两个不同的实例,内存地址也是不同的
    # t1 = Test("toby")
    # t2 = Test("ttr")
    # print(t1)
    # print(t2)

    #Demo类继承了实现了单例模式的OneOnly类,因此,通过Demo类实例化出来的对象都是同一个对象
    d1 = Demo("toby")
    d2 = Demo("ttr")
    d3 = Demo("laowang")
    # 通过打印可知,他们的内存地址都是一样的
    # print(d1)
    # print(d2)

    #发现打印出来的name都是"laowang",似乎最后创建的一个实例把前两个的给覆盖了
    d1.show_name()
    d2.show_name()
    d3.show_name()

    #通过实例d1修改名字后,再通过实例d3和d2来查看,果然也一起改变了。由此证明他们确实是同一个实例
    d1.chage_name("juck")
    d3.show_name()
    d2.show_name()

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • python - 面向对象

    --------------------------------------------------------------------------------...

    py3study
  • Python学习手册之类和继承

    在上一篇文章中,我们介绍了 Python 的函数式编程,现在我们介绍 Python 的类和继承。

    py3study
  • python学习笔记:第17天 面向对象

    ⼤千世界, 万物之间皆有规则和规律. 我们的类和对象是对⼤千世界中的所有事物进⾏归类. 那事物之间存在着相对应的关系. 类与类之间也同样如此. 在⾯向对象的世界...

    py3study
  • 如何理解“面向对象”编程思想

    面向对象 ( Object Oriented ) 是将现实问题构建关系,然后抽象成 类 ( class ),给类定义属性和方法后,再将类实例化成 实例 ( in...

    张凯强
  • Python权威指南的10个项目(1~5

    引言:   我相信学习Python过的朋友,一定会喜欢上这门语言,简单,库多,易上手,学习成本低,但是如果是学习之后,不经常使用,或者工作中暂时用不到,那么不久...

    py3study
  • PySpark工作原理

    Spark是一个开源的通用分布式计算框架,支持海量离线数据处理、实时计算、机器学习、图计算,结合大数据场景,在各个领域都有广泛的应用。Spark支持多种开发语言...

    Fayson
  • python pyqt5 控件间传递数据

    import sys from PyQt5.QtWidgets import QWidget, QLCDNumber, QSlider, QVBoxLayou...

    用户5760343
  • scrapy 传参

    shengjk1
  • Python的多态

    py3study
  • 绕过安全设备的0day

    DNS域名系统是互联网关键的基础设施之一,它是一个将域名与IP地址互相映射的全球分布数据库。对于恶意DNS的过滤、检测恶意网站域名、僵尸网络和网络隐秘通道发现是...

    糖果

扫码关注云+社区

领取腾讯云代金券