day26 面向对象 单例模式总结

 

本文示例转载于知乎原文:

https://zhuanlan.zhihu.com/p/87524388

 

如果是在python2中,就需要手动继承object,

 基于__new__方法

class Singleton:
    def __new__(cls, *args, **kwargs):
        if not hasattr(cls, "_isinstance"):
            cls._isinstance = super().__new__(cls)
        return cls._isinstance

    def __init__(self, x):
        self.x = x


singleton = Singleton(89)
print(id(singleton))
print("before-singleton>>>", singleton.x)
single_2 = Singleton(78)
print(id(single_2))
print(single_2.x)
print("after-singleton>>>", singleton.x)

 

 基于装饰器方法

def foo(cls, *args, **kwargs):
    dic = {}

    def _foo():
        if cls not in dic:
            dic[cls] = cls(*args, **kwargs)
        return dic[cls]
    return _foo


@foo
class MyClass(object):
    def __init__(self):
        pass


my = MyClass()
my1 = MyClass()

print(id(my) == id(my1))

 

基于元类metaclass实现,not yet

 

在python3里面,super就不需要再加参数了,直接写成"super()"就行。 

 

知识点总结,封装,静态变量变成私有变量

 

单例模式,生产场景使用:数据库连接类,封装连接数据库的基础参数

class SqlClient(object):
    def __init__(self, host, user, passwd):
        self.host = host
        self.user = user
        self.passwd = passwd
        self.register()
    
    def register(self):
        self.info = "{}--{}---{}".format(self.host, self.user, self.passwd)
    
    def select(self):
        print("SELECT * FROM {}".format(self.host))

调用上面数据库连接类,做sql查询,如下是一种使用方法:

host = "10.293.291.19"
user = "admin"
passwd = "666666"
def use_data_1(sql_client):
    sql_client.select()
    
def use_data_2(sql_client):
    sql_client.select()
​
def use_data_3(sql_client):
    sql_client.select()
    
sql_client = SqlClient(host, user, passwd)
use_data_1(sql_client)
use_data_2(sql_client)
use_data_3(sql_client)

开发中我们应该意识到一个问题,尽量少传参数,尤其是链式调用的函数,只在其中某几个环境用到,我们却需要不断的把它当作参数一致往下传递,如果这样的话,我们会发现,我们会传递很多参数,比如下面的例子:

host = "10.293.291.19"
user = "admin"
passwd = "666666"
def use_data_1(sql_client):
    sql_client.select()
    use_data_2(sql_client)
    
def use_data_2(sql_client):
    use_data_3(sql_client)
​
def use_data_3(sql_client):
    sql_client.select()
    
sql_client = SqlClient(host, user, passwd)
use_data_1(sql_client)

 

下面用单例模式:

class Singleton(object):
    def __new__(cls, *args, **kw):
        if not hasattr(cls, '_instance'):
            orig = super(Singleton, cls)
            cls._instance = orig.__new__(cls, *args, **kw)
        return cls._instance
    


class SqlClient(Singleton):
    """构建单例模式,避免重复传参数"""
    
    info = None
    
    def register(self, host, user, passwd):
        self.info = "{}--{}--{}".format(host, user, passwd)
        
    def select(self):
        print(self.info)



# 使用单例模式
def use_data_1():
    SqlClient().select()
​
def use_data_2():
    SqlClient().select()
    
def use_data_3():
    SqlClient().select()
    
SqlClient().register(host, user, passwd)
use_data_1()
use_data_2()
use_data_3()

 

依此可以发散思维一下,凡是类似的场景都可以考虑一下是否可以使用单例模式。

当然,凡事既有优点就会有缺点,单例模式也是,它可以实现系统的整体性和统一性,但是也不是在任何场景下都是适用的,例如,

  • 多线程
  • 可变对象

在这些场景下,它违背了单例模式单一性原则,而且很容易引起数据错误。

因此,使用单例模式之前需要考虑一下对应场景是否适合,如果适合,单例模式能够大大提高代码的效率,同时使得代码更加简洁,但是如果不适合而强行使用单例模式,那样会导致很多未知的问题。

本文示例转载于知乎原文:

https://zhuanlan.zhihu.com/p/87524388

 

posted @ 2018-05-28 21:58  dream-子皿  阅读(124)  评论(0编辑  收藏  举报