python设计模式

1.创建型模式

单例模式

单例模式(Singleton Pattern)是一种常用的软件设计模式,该模式的主要目的是确保某一个类只有一个实例存在。当你希望在整个系统中,某个类只能出现一个实例时,单例对象就能派上用场。

比如,某个服务器程序的配置信息存放在一个文件中,客户端通过一个 AppConfig 的类来读取配置文件的信息。如果在程序运行期间,有很多地方都需要使用配置文件的内容,也就是说,很多地方都需要创建 AppConfig 对象的实例,这就导致系统中存在多个 AppConfig 的实例对象,而这样会严重浪费内存资源,尤其是在配置文件内容很多的情况下。事实上,类似 AppConfig 这样的类,我们希望在程序运行期间只存在一个实例对象


class Singleton(object):
    def __init__(self):
        pass

    def __new__(cls, *args, **kwargs):
        if not hasattr(Singleton, "_instance"):
            Singleton._instance = object.__new__(cls)
        return Singleton._instance


obj1 = Singleton()
obj2 = Singleton()

print(obj1, obj2)  # <__main__.Singleton object at 0x000001F2C74E4D08> <__main__.Singleton object at 0x000001F2C74E4D08>

工厂模式

工厂模式是一个在软件开发中用来创建对象的设计模式。

工厂模式包涵一个超类。这个超类提供一个抽象化的接口来创建一个特定类型的对象,而不是决定哪个对象可以被创建。

为了实现此方法,需要创建一个工厂类创建并返回。 

当程序运行输入一个“类型”的时候,需要创建于此相应的对象。这就用到了工厂模式。在如此情形中,实现代码基于工厂模式,可以达到可扩展,可维护的代码。当增加一个新的类型,不在需要修改已存在的类,只增加能够产生新类型的子类。

简短的说,当以下情形可以使用工厂模式:

1.不知道用户想要创建什么样的对象

2.当你想要创建一个可扩展的关联在创建类与支持创建对象的类之间。

一个例子更能很好的理解以上的内容:

  1. 我们有一个基类Person ,包涵获取名字,性别的方法 。有两个子类male 和female,可以打招呼。还有一个工厂类。
  2.  工厂类有一个方法名getPerson有两个输入参数,名字和性别。
  3.  用户使用工厂类,通过调用getPerson方法。

在程序运行期间,用户传递性别给工厂,工厂创建一个与性别有关的对象。因此工厂类在运行期,决定了哪个对象应该被创建


class Person:
    def __init__(self):
        self.name = None
        self.gender = None

    def getName(self):
        return self.name

    def getGender(self):
        return self.gender


class Male(Person):
    def __init__(self, name):
        print("Hello Mr " + name)


class Female(Person):
    def __init__(self, name):
        print("Hello Miss " + name)


class Factory:
    def getPerson(self, name, gender):
        if gender == "M":
            return Male(name)
        if gender == "F":
            return Female(name)

if __name__ == '__main__':
    factory = Factory()
    person = factory.getPerson("zhangsan", "M")
    print(person)

建造者模式

将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。

相关模式:思路和模板方法模式很像,模板方法是封装算法流程,对某些细节,提供接口由子类修改,建造者模式更为高层一点,将所有细节都交由子类实现。例如C++模板中可以定义一个类实现数字可以相加,字符串也可以相加的功能,模板中只要传入相应的类型底层就可以自动判断是字符串还是数字,并且返回指定的结果

一个例子更能很好的理解以上的内容:

1. 有一个接口类,定义创建对象的方法。一个指挥员类,接受创造者对象为参数。两个创造者类,创建对象方法相同,内部创建可自定义

2.一个指挥员,两个创造者(瘦子 胖子),指挥员可以指定由哪个创造者来创造

from abc import ABCMeta, abstractmethod

class Builder():
    __metaclass__ = ABCMeta

    @abstractmethod
    def draw_left_arm(self):
        pass

    @abstractmethod
    def draw_right_arm(self):
        pass

    @abstractmethod
    def draw_left_foot(self):
        pass

    @abstractmethod
    def draw_right_foot(self):
        pass

    @abstractmethod
    def draw_head(self):
        pass

    @abstractmethod
    def draw_body(self):
        pass


class Thin(Builder):

    def draw_left_arm(self):
        print("画左手")

    def draw_right_arm(self):
        print("画右手")

    def draw_left_foot(self):
        print("画左脚")

    def draw_right_foot(self):
        print("画右脚")

    def draw_head(self):
        print("画头")

    def draw_body(self):
        print("画瘦身体")


class Fat(Builder):

    def draw_left_arm(self):
        print("画左手")

    def draw_right_arm(self):
        print("画右手")

    def draw_left_foot(self):
        print("画左脚")

    def draw_right_foot(self):
        print("画右脚")

    def draw_head(self):
        print("画头")

    def draw_body(self):
        print("画胖身体")


class Director():
    def __init__(self, person):
        self.person = person

    def draw(self):
        self.person.draw_left_arm()
        self.person.draw_right_arm()
        self.person.draw_left_foot()
        self.person.draw_right_foot()
        self.person.draw_head()
        self.person.draw_body()


if __name__ == '__main__':
    thin = Thin()
    fat = Fat()
    director_thin = Director(thin)
    director_thin.draw()
    director_fat = Director(fat)
    director_fat.draw()

原型模式

用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。
原型模式本质就是克隆对象,所以在对象初始化操作比较复杂的情况下,很实用,能大大降低耗时,提高性能,因为“不用重新初始化对象,而是动态地获得对象运行时的状态”。

浅拷贝(Shallow Copy):指对象的字段被拷贝,而字段引用的对象不会被拷贝,拷贝的对象和源对象只是名称相同,但是他们共用一个实体。
深拷贝(deep copy):对对象实例中字段引用的对象也进行拷贝。

import copy
from collections import OrderedDict

class Book:
    def __init__(self, name, authors, price, **rest):
        """rest的例子有:出版商,长度,标签,出版日期"""
        self.name = name
        self.authors = authors
        self.price = price
        self.__dict__.update(rest)

    def __str__(self):
        mylist = []
        ordered = OrderedDict(sorted(self.__dict__.items()))
        for i in ordered.keys():
            mylist.append('{}: {}'.format(i, ordered[i]))
            if i == 'price':
                mylist.append('$')
            mylist.append('\n')
        return ''.join(mylist)

class Prototype:
    def __init__(self):
        self.objects = dict()

    def register(self, identifier, obj):
        self.objects[identifier] = obj

    def unregister(self, identifier):
        del self.objects[identifier]

    def clone(self, identifier, **attr):
        found = self.objects.get(identifier)
        if not found:
            raise ValueError('incorrect object identifier: {}'.format(identifier))
        obj = copy.deepcopy(found)
        obj.__dict__.update(attr)
        return obj

def main():
    b1 = Book('The C Programming Language', ('Brian W. Kernighan', 'Dennis M.Ritchie'),
              price=118, publisher='Prentice Hall', length=228, publication_date='1978-02-22',
              tags=('C', 'programming', 'algorithms', 'data structures'))
    prototype = Prototype()
    cid = 'k&r-first'
    prototype.register(cid, b1)
    b2 = prototype.clone(cid, name='The C Programming Language(ANSI)', price=48.99,
                         length=274, publication_date='1988-04-01', edition=2)

    print(b1)
    print(b2)
    print("ID b1 : {} != ID b2 : {}".format(id(b1), id(b2)))

if __name__ =='__main__':
    main()

'''
C:/Users/wangxianchao/PycharmProjects/PythonStudy/多线程.py
odict_keys(['authors', 'length', 'name', 'price', 'publication_date', 'publisher', 'tags'])
authors: ('Brian W. Kernighan', 'Dennis M.Ritchie')
length: 228
name: The C Programming Language
price: 118$
publication_date: 1978-02-22
publisher: Prentice Hall
tags: ('C', 'programming', 'algorithms', 'data structures')

odict_keys(['authors', 'edition', 'length', 'name', 'price', 'publication_date', 'publisher', 'tags'])
authors: ('Brian W. Kernighan', 'Dennis M.Ritchie')
edition: 2
length: 274
name: The C Programming Language(ANSI)
price: 48.99$
publication_date: 1988-04-01
publisher: Prentice Hall
tags: ('C', 'programming', 'algorithms', 'data structures')

ID b1 : 1922565623240 != ID b2 : 1922565694600

Process finished with exit code 0

'''

2.结构性模式

适配器模式

修饰器模式

外观模式

享元模式

模型-视图-控制器模式

代理模式

3.行为模式

责任链模式

命令模式

解释器模式

观察者模式

状态 模式

策略模式

模板模式

上一篇:杭电OJ第11页2045~2049算法题(C语言)


下一篇:多态