资讯专栏INFORMATION COLUMN

Python下的设计模式总结----创建型设计模式(一)

lewif / 1541人阅读

摘要:最近在学习设计模式而开发的语言中比较中意的就是了在这里总结下设计模式一般分为三大类构造型结构型行为型先从创建型设计模式开始创建型设计模式包括单例模式抽象工厂模式工厂方法模式生成器模式惰性初始化模式对象池模式原型模式单例模式单例模式的定义是保

最近在学习设计模式,而开发的语言中比较中意的就是python了,在这里总结下.

设计模式一般分为三大类:构造型,结构型,行为型

先从创建型设计模式开始,创建型设计模式包括:单例模式,抽象工厂模式,工厂方法模式,生成器模式,惰性初始化模式,对象池模式,原型模式.

单例模式

单例模式的定义是:保证一个类仅有一个实例,并提供一个它的全局访问点.
先来看看14年前(没写错)的前辈介绍的单例模式例程

from __future__ import print_function


class Borg:
    __shared_state = {}

    def __init__(self):
        self.__dict__ = self.__shared_state
        self.state = "Init"

    def __str__(self):
        return self.state


class YourBorg(Borg):
    pass


if __name__ == "__main__":
    rm1 = Borg()
    rm2 = Borg()

    rm1.state = "Idle"
    rm2.state = "Running"

    print("rm1:{0}".format(rm1))
    print("rm2:{0}".format(rm2))

    rm2.state = "Zombie"

    print("rm1:{0}".format(rm1))
    print("rm2:{0}".format(rm2))

    print("rm1 id:{0}".format(id(rm1)))
    print("rm2 id:{0}".format(id(rm2)))

    rm3 = YourBorg()

    print("rm1:{0}".format(rm1))
    print("rm2:{0}".format(rm2))
    print("rm3:{0}".format(rm3))


# Output
# rm1:Running
# rm2:Running
# rm1:Zombie
# rm2:Zombie
# rm1 id:140609170593696
# rm2 id:140609170593624
# rm1:Init
# rm2:Init
# rm3:Init

简单解释下,需要get的点是下面这段代码

    __shared_state = {}
    
    def __init__(self):
        self.__dict__ = self.__shared_state
        self.state = "Init"

self.__dict__是对象的字典表示.将对象的属性设为全局静态变量.
根据输出结果,rm1和rm2俨然是一个实例.然而打印出来的rm1,rm2的变量id是不一致的,所以rm1,rm2并不是同一个实例.但是却有同样的状态和行为.但从结果上来看,确实实现了单例模式的要求.(虽然有种走捷径的感觉)

下面看看另一个版本的,其实就是换个形式,原理还是建多个实例,表现一致.其他部分的代码和上面的一致.

class Borg(object):
    __state = {}

    def __new__(cls, *p, **k):
        self = object.__new__(cls, *p, **k)
        self.__dict__ = cls.__state
        return self

    def __init__(self):
        self.state = "Init"

单例模式的创建有很多种方式.
这里有讨论链接描述

升级版,通过__metaclass__实现.这个版本中同一个id说明是同一个对象.

class Singleton(type):

    def __init__(self, name, bases, dict):
        super(Singleton, self).__init__(name, bases, dict)
        self._instance = None

    def __call__(self, *args, **kw):
        if self._instance is None:
            self._instance = super(Singleton, self).__call__(*args, **kw)
        return self._instance


class MyClass(object):
    __metaclass__ = Singleton


one = MyClass()
two = MyClass()

two.a = 3
print one.a
# 3
print id(one)
# 139798461922256

print id(two)
# 139798461922256

print one == two
# True

print one is two
# True

还可以通过装饰器来实现.这是第一个方法的高级版本,更pythonic,更elegant的方法.
这个例子中,单例类本身不知道自己是单例的,应为他本身(自己的代码)就不是单例的.

def singleton(cls, *args, **kw):
    instances = {}

    def _singleton():
        if cls not in instances:
            instances[cls] = cls(*args, **kw)
        return instances[cls]
    return _singleton


@singleton
class MyClass(object):
    a = 1

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


one = MyClass()
two = MyClass()

two.a = 3
print one.a
# 3

print id(one)
# 140630714076048

print id(two)
# 140630714076048

print one == two
# True

print one is two
# True

one.x = 1

print one.x
# 1

print two.x
# 1

好东西留到最后,来个超级无敌版的

class Singleton:
    """
    A non-thread-safe helper class to ease Implementing singletons.
    This should be used as a decorator -- not a metaclass -- to the
    class that should be singleton.

    The decorated class can define one `__init__` function that
    takes onelythe `self` argument. Other than that, there are no
    restrictions that apply to the decorated class.

    To get the singleton instances, use the `instances` method. Trying
    to use `__call__` will result in a `TypeError` being raised.

    Limitations: The decorated class cannot be inherited from.
    """

    def __init__(self, decorated):
        self._decorated = decorated

    def instance(self):
        """
        Return the singleton instance. Upon this first call, it creates
        a new instance of decorated class and calls its `__init__` method.
        On all subsequent calls, the already created instance is returned.
        """
        try:
            return self._instance
        except AttributeError:
            self._instance = self._decorated()
            return self._instance

    def __call__(self):
        raise TypeError("Singletons must be accessed through `instance()`.")

    def __instancecheck(self, inst):
        return isinstance(inst, self._decorated)


@Singleton
class Foo:
    def __init__(self):
        print "Foo created"


# f = Foo()
# TypeError: Singletons must be accessed through `instance()`.

f = Foo.instance()
g = Foo.instance()
# Foo created

print f is g
# True

关于python的单例模式,各家说法不一.可以根据不同的需求,使用不同的方式,适合的才是最好的.

参考文字:
https://zh.wikipedia.org/wiki/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F_(%E8%AE%A1%E7%AE%97%E6%9C%BA)

http://ginstrom.com/scribbles/2007/10/08/design-patterns-python-style/

http://code.activestate.com/recipes/66531/

http://blog.csdn.net/ghostfromheaven/article/details/7671853

http://stackoverflow.com/questions/31875/is-there-a-simple-elegant-way-to-define-singletons-in-python/31887#31887

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/37691.html

相关文章

  • J2EE下的常用设计模式

    摘要:当然,除了让我们显得更加专业之外,在自己所学习或者工作的项目中,适当合理的使用设计模式,能够给项目带来很大的好处。 简单说两句 本文首发公众号【一名打字员】 对不住各位老铁了,年前说好要更几波JAVA的东西,又偷懒了,没办法,在这里用小锤锤偷偷锤了自己几下。由于工作原因,更新时间不定,各位老铁有问题可以私聊我哈。 对于初学者或者是正在向中高级的Java程序猿(打字员)来说,时刻梳理自己...

    robin 评论0 收藏0
  • Java开发

    摘要:大多数待遇丰厚的开发职位都要求开发者精通多线程技术并且有丰富的程序开发调试优化经验,所以线程相关的问题在面试中经常会被提到。将对象编码为字节流称之为序列化,反之将字节流重建成对象称之为反序列化。 JVM 内存溢出实例 - 实战 JVM(二) 介绍 JVM 内存溢出产生情况分析 Java - 注解详解 详细介绍 Java 注解的使用,有利于学习编译时注解 Java 程序员快速上手 Kot...

    Lucky_Boy 评论0 收藏0
  • Java开发

    摘要:大多数待遇丰厚的开发职位都要求开发者精通多线程技术并且有丰富的程序开发调试优化经验,所以线程相关的问题在面试中经常会被提到。将对象编码为字节流称之为序列化,反之将字节流重建成对象称之为反序列化。 JVM 内存溢出实例 - 实战 JVM(二) 介绍 JVM 内存溢出产生情况分析 Java - 注解详解 详细介绍 Java 注解的使用,有利于学习编译时注解 Java 程序员快速上手 Kot...

    LuDongWei 评论0 收藏0
  • 7天学会3门语言,第

    摘要:天入门三门编程语言,有可能嘛,尤其是对没有基础的同学来说对于想学好的编程的人来说,无论从哪一门语言开始入手,语言的本身其实并不是我们最应该的关心的,至少不是作为一个初学者首先关心的。 7天入门三门编程语言,有可能嘛,尤其是对没有基础的同学来说?对于想学好的编程的人来说,无论从哪一门语言开始入手,语言的本身其实并不是我们最应该的关心的,至少不是作为一个初学者首先关心的。 网络上,网友们争...

    aristark 评论0 收藏0
  • 7天学会3门语言,第

    摘要:天入门三门编程语言,有可能嘛,尤其是对没有基础的同学来说对于想学好的编程的人来说,无论从哪一门语言开始入手,语言的本身其实并不是我们最应该的关心的,至少不是作为一个初学者首先关心的。 7天入门三门编程语言,有可能嘛,尤其是对没有基础的同学来说?对于想学好的编程的人来说,无论从哪一门语言开始入手,语言的本身其实并不是我们最应该的关心的,至少不是作为一个初学者首先关心的。 网络上,网友们争...

    RebeccaZhong 评论0 收藏0

发表评论

0条评论

lewif

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<