美文网首页
创建型模式

创建型模式

作者: 英武 | 来源:发表于2017-03-12 23:37 被阅读76次

    创建型模式

    创建型模式有以下几种:
    Creational Patterns:

    Pattern Description
    singleton 仅仅实例化一次
    abstract_factory use a generic function with specific factories
    borg a singleton with shared-state among instances
    builder instead of using multiple constructors, builder object receives parameters and returns constructed objects
    factory_method delegate a specialized function/method to create instances
    lazy_evaluation lazily-evaluated property pattern in Python
    pool preinstantiate and maintain a group of instances of the same type
    prototype use a factory and clones of a prototype for new instances (if instantiation is expensive)

    已经花费了大量篇幅已经介绍了抽象工厂,建造者,工厂,原型这几个模式,没有介绍的是有单例,共享(borg),惰性求值和pool这几个模式,下面简单介绍下:

    对于singleton,如果你真的想使用其他编程语言中类似的“单例模式”,你需要看:

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

    http://ghostfromheaven.iteye.com/blog/1562618

    但是,我要问的是,Python真的需要单例模式吗?我指像其他编程语言中的单例模式。

    答案是:不需要!

    因为,Python有模块(module),最pythonic的单例典范。

    模块在在一个应用程序中只有一份,它本身就是单例的,将你所需要的属性和方法,直接暴露在模块中变成模块的全局变量和方法即可!

    http://stackoverflow.com/a/31887/1447185

    下面是四种方法实现了singleton,可以参考以下。

    #-*- encoding=utf-8 -*-
    print '----------------------方法1--------------------------'
    #方法1,实现__new__方法
    #并在将一个类的实例绑定到类变量_instance上,
    #如果cls._instance为None说明该类还没有实例化过,实例化该类,并返回
    #如果cls._instance不为None,直接返回cls._instance
    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 MyClass(Singleton):
        a = 1
    
    one = MyClass()
    two = MyClass()
    
    two.a = 3
    print one.a
    #3
    #one和two完全相同,可以用id(), ==, is检测
    print id(one)
    #29097904
    print id(two)
    #29097904
    print one == two
    #True
    print one is two
    #True
    
    print '----------------------方法2--------------------------'
    #方法2,共享属性;所谓单例就是所有引用(实例、对象)拥有相同的状态(属性)和行为(方法)
    #同一个类的所有实例天然拥有相同的行为(方法),
    #只需要保证同一个类的所有实例具有相同的状态(属性)即可
    #所有实例共享属性的最简单最直接的方法就是__dict__属性指向(引用)同一个字典(dict)
    #可参看:http://code.activestate.com/recipes/66531/
    class Borg(object):
        _state = {}
        def __new__(cls, *args, **kw):
            ob = super(Borg, cls).__new__(cls, *args, **kw)
            ob.__dict__ = cls._state
            return ob
    
    class MyClass2(Borg):
        a = 1
    
    one = MyClass2()
    two = MyClass2()
    
    #one和two是两个不同的对象,id, ==, is对比结果可看出
    two.a = 3
    print one.a
    #3
    print id(one)
    #28873680
    print id(two)
    #28873712
    print one == two
    #False
    print one is two
    #False
    #但是one和two具有相同的(同一个__dict__属性),见:
    print id(one.__dict__)
    #30104000
    print id(two.__dict__)
    #30104000
    
    print '----------------------方法3--------------------------'
    #方法3:本质上是方法1的升级(或者说高级)版
    #使用__metaclass__(元类)的高级python用法
    class Singleton2(type):
        def __init__(cls, name, bases, dict):
            super(Singleton2, cls).__init__(name, bases, dict)
            cls._instance = None
        def __call__(cls, *args, **kw):
            if cls._instance is None:
                cls._instance = super(Singleton2, cls).__call__(*args, **kw)
            return cls._instance
    
    class MyClass3(object):
        __metaclass__ = Singleton2
    
    one = MyClass3()
    two = MyClass3()
    
    two.a = 3
    print one.a
    #3
    print id(one)
    #31495472
    print id(two)
    #31495472
    print one == two
    #True
    print one is two
    #True
    
    print '----------------------方法4--------------------------'
    #方法4:也是方法1的升级(高级)版本,
    #使用装饰器(decorator),
    #这是一种更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 MyClass4(object):
        a = 1
        def __init__(self, x=0):
            self.x = x
    
    one = MyClass4()
    two = MyClass4()
    
    two.a = 3
    print one.a
    #3
    print id(one)
    #29660784
    print id(two)
    #29660784
    print one == two
    #True
    print one is two
    #True
    one.x = 1
    print one.x
    #1
    print two.x
    #1
    

    对于共享(borg)模式,主要来自于star trek中的borg种族的特性。可以参考以下代码:

    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    
    
    class Borg(object):
        __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: 140732837899224
    # rm2 id: 140732837899296
    # rm1: Init
    # rm2: Init
    # rm3: Init
    

    主要还是要关注这条语句:

        self.__dict__ = self.__shared_state
    

    通过这条语句实现了共享。

    下面看以下惰性求值,lazy_evaluation模式:

    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    
    """
    Lazily-evaluated property pattern in Python.
    https://en.wikipedia.org/wiki/Lazy_evaluation
    References:
    bottle
    https://github.com/bottlepy/bottle/blob/cafc15419cbb4a6cb748e6ecdccf92893bb25ce5/bottle.py#L270
    django
    https://github.com/django/django/blob/ffd18732f3ee9e6f0374aff9ccf350d85187fac2/django/utils/functional.py#L19
    pip
    https://github.com/pypa/pip/blob/cb75cca785629e15efb46c35903827b3eae13481/pip/utils/__init__.py#L821
    pyramimd
    https://github.com/Pylons/pyramid/blob/7909e9503cdfc6f6e84d2c7ace1d3c03ca1d8b73/pyramid/decorator.py#L4
    werkzeug
    https://github.com/pallets/werkzeug/blob/5a2bf35441006d832ab1ed5a31963cbc366c99ac/werkzeug/utils.py#L35
    """
    
    from __future__ import print_function
    import functools
    
    
    class lazy_property(object):
    
        def __init__(self, function):
            self.function = function
            functools.update_wrapper(self, function)
    
        def __get__(self, obj, type_):
            if obj is None:
                return self
            val = self.function(obj)
            obj.__dict__[self.function.__name__] = val
            return val
    
    
    class Person(object):
    
        def __init__(self, name, occupation):
            self.name = name
            self.occupation = occupation
    
        @lazy_property
        def relatives(self):
            # Get all relatives, let's assume that it costs much time.
            relatives = "Many relatives."
            return relatives
    
    
    def main():
        Jhon = Person('Jhon', 'Coder')
        print(u"Name: {0}    Occupation: {1}".format(Jhon.name, Jhon.occupation))
        print(u"Before we access `relatives`:")
        print(Jhon.__dict__)
        print(u"Jhon's relatives: {0}".format(Jhon.relatives))
        print(u"After we've accessed `relatives`:")
        print(Jhon.__dict__)
    
    
    if __name__ == '__main__':
        main()
    
    ### OUTPUT ###
    # Name: Jhon    Occupation: Coder
    # Before we access `relatives`:
    # {'name': 'Jhon', 'occupation': 'Coder'}
    # Jhon's relatives: Many relatives.
    # After we've accessed `relatives`:
    # {'relatives': 'Many relatives.', 'name': 'Jhon', 'occupation': 'Coder'}
    

    pool模式非常的好理解,就是用Queue实现了一个生产者/消费者模型,queue模块是线程安全的,下面的stackoverflow的链接
    主要就是介绍了想要实现一个pool,里面存放一些网络的连接,因为如果每次建立连接,系统开销比较大。使用queue模块非常合适。

    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    
    """
    http://stackoverflow.com/questions/1514120/python-implementation-of-the-object-pool-design-pattern
    """
    
    
    
    class ObjectPool(object):
    
        def __init__(self, queue, auto_get=False):
            self._queue = queue
            self.item = self._queue.get() if auto_get else None
    
        def __enter__(self):
            if self.item is None:
                self.item = self._queue.get()
            return self.item
    
        def __exit__(self, Type, value, traceback):
            if self.item is not None:
                self._queue.put(self.item)
                self.item = None
    
        def __del__(self):
            if self.item is not None:
                self._queue.put(self.item)
                self.item = None
    
    
    def main():
        try:
            import queue
        except ImportError:  # python 2.x compatibility
            import Queue as queue
    
        def test_object(queue):
            pool = ObjectPool(queue, True)
            print('Inside func: {}'.format(pool.item))
    
        sample_queue = queue.Queue()
    
        sample_queue.put('yam')
        with ObjectPool(sample_queue) as obj:
            print('Inside with: {}'.format(obj))
        print('Outside with: {}'.format(sample_queue.get()))
    
        sample_queue.put('sam')
        test_object(sample_queue)
        print('Outside func: {}'.format(sample_queue.get()))
    
        if not sample_queue.empty():
            print(sample_queue.get())
    
    
    if __name__ == '__main__':
        main()
    
    ### OUTPUT ###
    # Inside with: yam
    # Outside with: yam
    # Inside func: sam
    # Outside func: sam
    

    相关文章

      网友评论

          本文标题:创建型模式

          本文链接:https://www.haomeiwen.com/subject/pkoxnttx.html