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"))


你可能感兴趣的:(python设计模式(持续更新))