Python设计模式学习笔记

作者:闫辉  Email:[email protected]


创建型设计模式

 

  • 抽象工厂(Abstract Factory)

"""
*这种模式是什么?

在Java和其他语言中,抽象工厂模式用于提供接口,创建相关/依赖的对象,而无需指定对象的实际类。
其思想是,将依赖于业务逻辑、平台选择等因素的对象创建,进行抽象。
在Python中,我们使用的接口是一个简单的callabe,它是“内置”的接口。
在Python中,一般情况下,我们可以简单地使用类本身,来作为那个callable,因为类是Python中的头等对象。

*以下示例代码做了什么?

这个特定的实现,抽象了pet的创建。此创建取决于我们选择的工厂(Dog或Cat,或random_animal)。
这是可行的,因为Dog/Cat和random_animal都遵守一个通用的interface(对象创建和.speak()都是callable)。
现在,应用程序可以抽象地创建pet,稍后根据自己的准则,决定是dog还是cat。

*这种模式的实际应用?

*参考资料:
https://sourcemaking.com/design_patterns/abstract_factory
http://ginstrom.com/scribbles/2007/10/08/design-patterns-python-style/

*TL;DR80
提供封装一组单个工厂的方法。
"""

import random


class PetShop(object):

    """A pet shop"""

    def __init__(self, animal_factory=None):
        """pet_factory is our abstract factory.  We can set it at will."""

        self.pet_factory = animal_factory

    def show_pet(self):
        """Creates and shows a pet using the abstract factory"""

        pet = self.pet_factory()
        print("We have a lovely {}".format(pet))
        print("It says {}".format(pet.speak()))


class Dog(object):
    def speak(self):
        return "woof"

    def __str__(self):
        return "Dog"


class Cat(object):
    def speak(self):
        return "meow"

    def __str__(self):
        return "Cat"


# Additional factories:

# Create a random animal
def random_animal():
    """Let's be dynamic!"""
    return random.choice([Dog, Cat])()


# Show pets with various factories
if __name__ == "__main__":

    # A Shop that sells only cats
    cat_shop = PetShop(Cat)
    cat_shop.show_pet()
    print("")

    # A shop that sells random animals
    shop = PetShop(random_animal)
    for i in range(3):
        shop.show_pet()
        print("=" * 20)

### OUTPUT ###
# We have a lovely Cat
# It says meow
#
# We have a lovely Dog
# It says woof
# ====================
# We have a lovely Cat
# It says meow
# ====================
# We have a lovely Cat
# It says meow
# ====================
  • 工厂方法(Factory Method)

"""
*这种模式是什么?
工厂方法模式可用于为a方法创建一个接口,将实现留给可实例化的类。

*以下示例代码做了什么?
该代码显示了一种用英语和希腊语本地化单词的方法。
"getLocalizer"是一个工厂方法,它根据所选择的语言,构造了一个本地化器对象。
本地化器对象是不同类的实例,这些不同类取决于被本地化的语言。
不过,主代码不必担心哪个本地化器被实例化,因为方法"get"与所选择的语言无关,它以同样的方式被调用。

*这种模式的实际应用?
在流行的Web框架Django中,可以看到工厂方法:
http://django.wikispaces.asu.edu/*NEW*+Django+Design+Patterns
例如,在一个网页的联系人表单中,尽管subject和message字段的目的不同,实现也不相同,
但是它们是用同一个表单工厂(CharField())创建的。


*参考文献:
http://ginstrom.com/scribbles/2007/10/08/design-patterns-python-style/
https://fkromer.github.io/python-pattern-references/design/#factory-method
https://sourcemaking.com/design_patterns/factory_method

* TL;DR80
无需指定确切的类即可创建对象。
"""

class GreekGetter(object):

    """A simple localizer a la gettext"""

    def __init__(self):
        self.trans = dict(dog="σκύλος", cat="γάτα")

    def get(self, msgid):
        """We'll punt if we don't have a translation"""
        return self.trans.get(msgid, str(msgid))


class EnglishGetter(object):

    """Simply echoes the msg ids"""

    def get(self, msgid):
        return str(msgid)


def get_localizer(language="English"):
    """The factory method"""
    languages = dict(English=EnglishGetter, Greek=GreekGetter)
    return languages[language]()


if __name__ == '__main__':
    # Create our localizers
    e, g = get_localizer(language="English"), get_localizer(language="Greek")
    # Localize some text
    for msgid in "dog parrot cat bear".split():
        print(e.get(msgid), g.get(msgid))

### OUTPUT ###
# dog σκύλος
# parrot parrot
# cat γάτα
# bear bear
  • Builder(建造者)

"""
*这种模式是什么?
它解耦了复杂对象的创建和表示,这样就可以重用相同的过程,从同一对象家族中构建对象。
当您必须将对象的规范与它的实际表示分离时(通常用于抽象),这种模式很有用。

*这个例子做了什么?
第一个例子通过使用抽象的基类来实现构建。
初始化器(__init__方法)指定了必需的步骤,具体的子类实现了这些步骤。

在其他编程语言中,有时必须采用更复杂的做法。
特别是,你不能在C++的构造函数中有多态行为。
请参阅 
https://stackoverflow.com/questions/1453131/how-can-i-get-polymorphic-behavior-in-ac-constructor
——这意味着这种Python技术不起作用。所需的多态性,必须由外部已构造的其他类的实例来提供。

一般而言,在Python中这不是必需的,不过,以下包含的第二个例子演示了这种做法。

*实际使用的模式在哪里?

*参考文献:
https://sourcemaking.com/design_patterns/builder

* TL; DR80
解耦复杂对象及其表示的创建。
"""

# Abstract Building
class Building(object):
    def __init__(self):
        self.build_floor()
        self.build_size()

    def build_floor(self):
        raise NotImplementedError

    def build_size(self):
        raise NotImplementedError

    def __repr__(self):
        return 'Floor: {0.floor} | Size: {0.size}'.format(self)


# Concrete Buildings
class House(Building):
    def build_floor(self):
        self.floor = 'One'

    def build_size(self):
        self.size = 'Big'


class Flat(Building):
    def build_floor(self):
        self.floor = 'More than One'

    def build_size(self):
        self.size = 'Small'


# In some very complex cases, it might be desirable to pull out the building
# logic into another function (or a method on another class), rather than being
# in the base class '__init__'. (This leaves you in the strange situation where
# a concrete class does not have a useful constructor)


class ComplexBuilding(object):
    def __repr__(self):
        return 'Floor: {0.floor} | Size: {0.size}'.format(self)


class ComplexHouse(ComplexBuilding):
    def build_floor(self):
        self.floor = 'One'

    def build_size(self):
        self.size = 'Big and fancy'


def construct_building(cls):
    building = cls()
    building.build_floor()
    building.build_size()
    return building


# Client
if __name__ == "__main__":
    house = House()
    print(house)
    flat = Flat()
    print(flat)

    # Using an external constructor function:
    complex_house = construct_building(ComplexHouse)
    print(complex_house)

### OUTPUT ###
# Floor: One | Size: Big
# Floor: More than One | Size: Small
# Floor: One | Size: Big and fancy
  • 原型(Prototype)

"""
*这种模式是什么?

这种模式旨在减少一个应用所需的类的数量。它不是依赖于子类,而是通过复制原型实例,在运行时创建对象。

当类的实例只有几个不同状态的组合,且实例化的开销很昂贵时,此模式很有用,因为它可以很容易地派生出新类型的对象。

*这个例子做了什么?

当应用程序中的原型的数量不一样时,保持一个Dispatcher(aka,Registry或Manager)是很有用的。
这允许客户端代码在克隆一个新的实例之前,针对某原型,查询此Dispatcher。

以下代码提供这样的Dispatcher的一个示例,其中包含了三个原型的副本: 'default','objecta'和'objectb'。

* TL; DR80
通过克隆原型创建新的对象实例。
"""

class Prototype(object):

    value = 'default'

    def clone(self, **attrs):
        """Clone a prototype and update inner attributes dictionary"""
        # Python in Practice, Mark Summerfield
        obj = self.__class__()
        obj.__dict__.update(attrs)
        return obj


class PrototypeDispatcher(object):
    def __init__(self):
        self._objects = {}

    def get_objects(self):
        """Get all objects"""
        return self._objects

    def register_object(self, name, obj):
        """Register an object"""
        self._objects[name] = obj

    def unregister_object(self, name):
        """Unregister an object"""
        del self._objects[name]


def main():
    dispatcher = PrototypeDispatcher()
    prototype = Prototype()

    d = prototype.clone()
    a = prototype.clone(value='a-value', category='a')
    b = prototype.clone(value='b-value', is_checked=True)
    dispatcher.register_object('objecta', a)
    dispatcher.register_object('objectb', b)
    dispatcher.register_object('default', d)
    print([{n: p.value} for n, p in dispatcher.get_objects().items()])


if __name__ == '__main__':
    main()

### OUTPUT ###
# [{'objectb': 'b-value'}, {'default': 'default'}, {'objecta': 'a-value'}]
  • 单例

import threading

class Singleton(object):
    ''''' A python style singleton '''
 
    _instance_lock = threading.Lock()

    def __new__(cls, *args, **kwargs):
        if not hasattr(cls, "_instance"):
            with cls._instance_lock:
                if not hasattr(cls, "_instance"):
                    cls._instance = super().__new__(cls, *args, **kwargs)
        return cls._instance

if __name__ == '__main__':
    s1=Singleton()
    s2=Singleton()
    print(id(s1),id(s2),id(s1)==id(s2))

 

你可能感兴趣的:(Python,Python,设计模式)