python设计模式(持续更新)

1.抽象工厂模式

import random


class PetShop(object):
    def __init__(self,animal_factory=None):
        #  pet 宠物  factory 工厂
        self.pet_factory = animal_factory

    def show_pet(self):
        pet = self.pet_factory.get_pet()
        print("this is a lovely", pet)
        print("it says",pet.speak())
        print("it eats",self.pet_factory.get_food())


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

    def __str__(self):
        return "this is Dog"


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

    def __str__(self):
        return "this is Cat"


class CatFactory:
    def get_pet(self):
        return Cat()

    def get_food(self):
        return "cat food"

class DogFactory:
    def get_pet(self):
        return Dog()

    def get_food(self):
        return "dog food"


def get_factory():
    return random.choice([DogFactory,CatFactory])

if __name__ == '__main__':
    shop = PetShop() # pet_factory 默认为None,后面延迟加载

    shop.pet_factory = get_factory()()  #  延迟加载,随机选择一个工厂然后实例出来一个对象给商店
    shop.show_pet()

2. 适配器模式

import os


class Dog:
    def __init__(self):
        self.name ="Dog"

    def bark(self): # bark :叫声
        return "woof!"  # woof 低吠声


class Cat:
    def __init__(self):
        self.name = "Cat"

    def meow(self):  # meow 猫叫声
        return "meow"   # meow 猫叫声


class Human:
    def __init__(self):
        self.name = "Human"

    def speak(self):
        return "hello, python"


class Car:
    def __init__(self):
        self.name = "Car"

    def make_noise(self, noise_level):
        return "noise level is {}".format(noise_level)


class Adapter: # adapter 适配器
    def __init__(self,obj,adapted_methods):   # adpted 适应
        self.obj = obj
        self.__dict__.update(adapted_methods)   # self.__dict__是打印对象所有的属性,结果是一个字典 {"kye":value}
        # key对应对象的属性,value对应属性的属性值。这里就相当于把不同类的方法都绑定到Adapter这个类实例化出来的
        # 对象的make_noise 属性上面去,该属性的值对应其他类里面的方法。

    def __getattr__(self, attr):  # 当调用类不存的属性或者方法时,就会触发该魔法方法
        return getattr(self.obj, attr)  # getattr(object,attr [,default])


def main():
    objects = []
    dog = Dog()
    objects.append(Adapter(dog,dict(make_noise=dog.bark)))
    cat = Cat()
    objects.append(Adapter(cat,dict(make_noise=cat.meow)))
    human = Human()
    objects.append(Adapter(human,dict(make_noise=human.speak)))
    car = Car()
    car_noise = lambda : car.make_noise(3)
    objects.append(Adapter(car,dict(make_noise=car_noise)))
    for obj in objects:
        print("A",obj.name,"goes",obj.make_noise())  # 这里 obj.make_noise 就相当于 dog.bark 这些方法,后面加括号代表执行
        print(obj.obj) # 原来的对象被存储到obj属性里面.

if __name__ == '__main__':
    # 适配器模式在不改变原有类的基础上,统一了所有的方法,还能够保存原有对象的引用obj属性
    main()



3.共享模式

class Borg:
    __shared_state = {}

    def __init__(self):
        self.state = None  # 设置默认值防止报错
        self.__dict__ = self.__shared_state  # 等号,浅拷贝,拷贝引用,
        # 后面实例化的对象的__dict__都是这个字典 __shared_state
        # 因为__shared_state 是类属性,所以只有一份,所有的实例对象共用

    def __str__(self):  # 打印对象的时候自动执行的魔法方法
        return self.state   # self.state动态添加


class YourBorg(Borg):

    def hhh(self):
        print(self.__shared_state)
    pass


if __name__ == '__main__':
    rm1 = Borg()
    rm2 = Borg()
    rm1.state = "Done"
    print("rm1.state:", rm1)   # rm1.state: Done
    print("rm1.state:", rm2)   # rm2.state: Done
    rm2.state = "Running"
    print("rm1.state:", rm1)   # rm1.state: Running
    print("rm2.state:", rm2)   # rm2.state: Running
    print("rm1 id:", id(rm1))   # rm1 id: 41601008
    print("rm2 id:", id(rm2))   # rm2 id: 41601064
    rm3 = YourBorg()     # 继承父类的__init__方法,但是私有属性没有继承。初始化的时候调用了父类的初始化方法
    # 下面2句注释证明上述观点
    # rm3.hhh()
    # print(rm3.__shared_state)
    print("rm3.state:", rm3)    # rm3.state: Running
    # 共享模式通过私有一个类属性,然后使用__dict__魔法方法共享所有的属性
    # 如果通过类属性共享属性,那么每有一个需要共享的属性就需要新建一个类属性

4.桥接模式

class DrawingAPI1:
    def draw_circle(self, x, y, radius):
        print("API1.circle at {} : {}  ,radius:{}".format(x, y, radius))


class DrawingAPI2:
    def draw_circle(self,x,y,radius):
        print("API2.cirle at {} : {}  ,radius:{}".format(x, y, radius))


class CircleShape:
    def __init__(self,x,y,radius,drawing_api):
        self._x = x
        self._y = y
        self._radius = radius
        self._drawing_api = drawing_api

    def draw(self):
        self._drawing_api.draw_circle(self._x,self._y,self._radius)

    def scale(self,pct):   # scale 规模
        self._radius *= pct   # pct 百分比


def main():
    shapes = (
        CircleShape(1,2,3,DrawingAPI1()),
        CircleShape(5,7,11,DrawingAPI2()),
    )  # 提供2个
    for shape in shapes:
        shape.scale(2.5)
        shape.draw()

if __name__ == '__main__':
    # 桥接模式就是一个类的属性的值是另一个类的实例对象。然后可以通过这个类的实例对象去调用另外一个类对象的方法
    main()

5.建造者模式

class Director:  # director 监视
    def __init__(self):
        self.builder = None  # builder建造者

    def construct_building(self):
        self.builder.new_building()
        self.builder.build_floor()
        self.builder.build_size()

    def get_building(self):
        return self.builder.building


class Builder:
    def __init__(self):
        self.building = None

    def new_building(self):
        self.building = Building()


class Building:
    def __init__(self):
        self.floor = None
        self.size = None

    def __repr__(self):   #  和__str__ 魔法方法类似,都是打印对象的时候调用,不过repr更强大
        # repr方法在交互式环境下也能起作用,即交互式环境直接输变量名打印的时候
        # __str__ 只有在print的时候才会触发
        return "Floor:%s | Size: %s" % (self.floor,self.size)


class BuilderHouse(Builder):
    def build_floor(self):
        self.building.floor = "One"

    def build_size(self):
        self.building.size = "Big"


class BuilderFlat(Builder):   # flat 公寓
    def build_floor(self):
        self.building.floor = "More than One"

    def build_size(self):
        self.building.size = "small"


if __name__ == '__main__':
    director = Director()
    director.builder = BuilderHouse()
    director.construct_building()
    building = director.get_building()
    print(building)
    director.builder = BuilderFlat()
    director.construct_building()
    building = director.get_building()
    print(building)

6.职责链模式

class Handler:
    def __init__(self):
        self.successor = None

    def add_successor(self,successor):  # successor 后续的事,继承者
        self.successor = successor


class ConcreteHandler1(Handler):
    def handle(self,request):
        if request>0 and request<=10:
            print("concreteHandler1 deal %s"%request)
        elif self.successor is not None:
            self.successor.handle(request)
        else:
            print("no handler can deal with %s"%request)


class ConcreteHandler2(Handler):
    def handle(self,request):
        if request>10 and request<=20:
            print("ConcreteHandler2 deal %s"%request)
        elif self.successor is not None:
            self.successor.handle(request)
        else:
            print("no handler can deal with %s" % request)

class ConcreteHandler3(Handler):
    def handle(self,request):
        if request>20 and request<=30:
            print("ConcreteHandler3 deal %s"%request)
        elif self.successor is not None:
            self.successor.handle(request)
        else:
            print("no handler can deal with %s" % request)


if __name__ == '__main__':
    h1 = ConcreteHandler1()  # 创建处理者1
    h2 = ConcreteHandler2()  # 创建处理者2
    h3 = ConcreteHandler3()  # 创建处理者3
    h1.add_successor(h2)  # 添加h1如果处理不了就让h2去处理
    h2.add_successor(h3)  # 如果h2处理不了就让h3去处理
    requests = [1,3,23,42,34,67,11,22,14,36]
    for request in requests:
        h1.handle(request)

7.命令模式

import os
class MoveFileCommand(object):
    def __init__(self,src,dest):
        self.src = src
        self.dest = dest

    def execute(self):
        self() # 直接调用对象本身会执行__call__方法

    def __call__(self, *args, **kwargs):  # __call__ 魔法方法直接调用对象的时候执行的方法
        print("renaming {} to {}".format(self.src,self.dest))
        os.rename(self.src,self.dest)

    def undo(self):
        print("renaming {} to {}".format(self.dest,self.src))
        os.rename(self.dest,self.src)


if __name__ == '__main__':
    command_stack = []
    command_stack.append(MoveFileCommand("foo.txt","bar.txt"))
    command_stack.append(MoveFileCommand("bar.txt","foo.txt"))

    for cmd in command_stack:
        cmd.execute()

    for cmd in reversed(command_stack):
        cmd.undo()

8.装饰器模式

class foo(object):
    def f1(self):
        print("func f1")

    def f2(self):
        print("func f2")


class foo_decorator(object):
    def __init__(self,decorator):
        self._decorator = decorator

    def f1(self):
        print("decorator f1")
        self._decorator.f1()

    def __getattr__(self, item):
        # 当得不到想要的属性时,就去自己的装饰里面拿,使用 getattr()内建方法
        return getattr(self._decorator,item)

if __name__ == '__main__':
    # 主要思想还是使用魔法方法 __getattr__ 方法, 然后把另外一个对象赋值到自身的属性上面.
    # 添加一个运行另外一个对象的接口,没有接口时,就去直接调用另一个对象的方法.
    u = foo()
    d = foo_decorator(u)
    d.f1()
    d.f2()

9.外观模式

class small_or_piece1:
    def __init__(self):
        pass

    def do_small1(self):
        print('do small 1')


class small_or_piece_2:
    def __init__(self):
        pass

    def do_small2(self):
        print('do small 2')


class small_or_piece_3:
    def __init__(self):
        pass

    def do_small3(self):
        print('do small 3')


class outside:
    def __init__(self):
        self.__small1 = small_or_piece1()
        self.__small2 = small_or_piece_2()
        self.__small3 = small_or_piece_3()

    def method1(self):
        self.__small1.do_small1()  ##如果这里调用的不只2两函数,作用就显示出来了,可以把原本复杂的函数调用关系清楚化,统一化
        self.__small2.do_small2()

    def method2(self):
        self.__small2.do_small2()
        self.__small3.do_small3()


if __name__ == '__main__':
    # 外观模式应用于在很多复杂而小功能需要调用时,并且这些调用还具有一定的相关性,即一调用就是一系列的调用.
    osd = outside()
    osd.method1()
    osd.method2()

10.单例模式

class A(object):
    __obj = False
    __init = False

    def __init__(self, name):
        if not A.__init:
            self.name = name
            A.__init = True

    def __new__(cls, *args, **kwargs):
        if not A.__obj:
            A.__obj = super().__new__(cls)
        return A.__obj


if __name__ == '__main__':
    # 只初始化一次的单例模式
    a = A("nick")
    b = A("nick2")
    print(a.name)  # nick
    print(b.name)  # nick
    print(a == b)  # True
    print(id(a), id(b))  # 54527760 54527760

11.图搜索模式

class GraphSearch:
    def __init__(self, graph):
        self.graph = graph

    def find_path(self, start, end, path=None):
        self.start = start
        self.end = end
        if not path:
            self.path = []
        self.path.extend([self.start])
        if self.start not in self.graph:
            return None  # 如果图里面没有这个start这个key,说明这条路不同,返回None
        if self.start == self.end:
            return self.path

        for node in self.graph[self.start]:
            if node not in self.path:
                newpath = self.find_path(node, self.end, self.path)
                if newpath:  # newpath不存在的时候说明这条路没有走通,继续循环,走下一条路
                    return newpath
        return None  # 如果上面一直没有return,走到这里说明从start没有找到end.返回None

    # def find_all_path(self, start, end, path=None, run_num=[]):
    #     self.start = start
    #     self.end = end
    #     if not path:
    #         self.path = []
    #     self.path.extend([self.start])
    #     paths = []
    #     if self.start not in self.graph:
    #         return []
    #     if self.start == self.end:
    #         if len(run_num) == 0:
    #             paths.append([self.start])
    #         else:
    #             return [self.path]
    #     for node in self.graph[self.start]:
    #         if node not in self.path:
    #             run_num.append(1)
    #             newpaths = self.find_all_path(node, self.end, self.path)
    #             for newpath in newpaths:
    #                 paths.append(newpath)
    #     return paths
    def find_all_path(self, start, end, path=None):
        self.start = start
        self.end = end
        if not path:
            self.path = []
        self.path += [self.start]
        if self.start == self.end:
            return [self.path]
        if self.start not in self.graph:
            return []
        paths = []
        for node in self.graph[self.start]:
            if node not in self.path:

                newpaths = self.find_all_path(node, self.end, self.path)
                for newpath in newpaths:
                    paths.append(newpath)
        return paths


    def find_shortest_path(self, start, end, path=None):
        self.start = start
        self.end = end
        if not path:
            self.path = []
        self.path.extend(self.start)
        if self.start not in self.graph:
            return None
        if self.start == self.end:
            return self.path

        shortpath = None
        for node in self.graph[self.start]:
            if node not in self.path:
                newpath = self.find_shortest_path(node, self.end, self.path)
                if newpath:
                    if not shortpath or len(newpath) < len(shortpath):
                        shortpath = newpath
        return shortpath


graph = {
    "A": ["B", "C"],
    'B': ['C', 'D'],
    'C': ['D'],
    'D': ['A'],
    'E': ['F'],
    'F': ['C']
}

graph1 = GraphSearch(graph)
print(graph1.find_path("A","D"))
print(graph1.find_all_path("A","A"))
print(graph1.find_all_path("A","D"))
print(graph1.find_shortest_path("A","D"))


最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,324评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,356评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,328评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,147评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,160评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,115评论 1 296
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,025评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,867评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,307评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,528评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,688评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,409评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,001评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,657评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,811评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,685评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,573评论 2 353

推荐阅读更多精彩内容

  • 设计模式汇总 一、基础知识 1. 设计模式概述 定义:设计模式(Design Pattern)是一套被反复使用、多...
    MinoyJet阅读 3,937评论 1 15
  • 设计模式基本原则 开放-封闭原则(OCP),是说软件实体(类、模块、函数等等)应该可以拓展,但是不可修改。开-闭原...
    西山薄凉阅读 3,792评论 3 14
  • 真诚的,TNANKS。 个人Github-23种设计模式案例链接 创建型模式 工厂模式 工厂模式(Factory ...
    水清_木秀阅读 26,050评论 11 204
  • 伍兰渴望的望着肖央,而她旁边的蔡月娥也是同样的表情。 “你们这是干什么,我烧的菜我自已知道,你们俩到底什么事,...
    回首已千年阅读 435评论 0 0
  • 中国之形式,他国之形式。他国之历史,我国之历史。无不相通。 无意刷剧看建军大业,一边看一边妄生许多感慨,之前有看见...
    RushQiang阅读 336评论 0 1