Python之设计模式

Posted 孟庆健

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python之设计模式相关的知识,希望对你有一定的参考价值。

一、设计模式分类

   a、创建型模式

  • 简单工厂模式
一、内容
不直接向客户端暴露对象创建的实现细节,而是通过一个工厂类来负责创建产品类的实例。 二、角色 工厂角色(Creator) 抽象产品角色(Product) 具体产品角色(Concrete Product)
三、优点 隐藏了对象创建的实现细节 客户端不需要修改代码
四、缺点 违反了单一职责原则,将创建逻辑集中到一个工厂类中 当添加新产品时,需要修改工厂类代码,违反了开放封闭原则

代码实例:

技术分享图片
from abc import abstractmethod,ABCMeta
class Payment(metaclass=ABCMeta):
    @abstractmethod
    def pay(self):
        pass

class Alipay(Payment):
    def __init__(self,money):
        self.money = money

    def pay(self):
        print(支付宝支付了%s元%self.money)

class Whatpay(Payment):
    def __init__(self, money):
        self.money = money

    def pay(self):
        print(微信支付了%s元 % self.money)


obj = Alipay(100)
obj.pay()

obj2 = Whatpay(200)
obj2.pay()
初始的
from abc import abstractmethod,ABCMeta
class Payment(metaclass=ABCMeta):
    @abstractmethod
    def pay(self,money):
        pass

class Alipay(Payment):
    def pay(self, money):
        print(支付宝支付了%s元%money)

class Applepay(Payment):
    def pay(self, money):
        print(微信支付了%s元 %money)

class Yuebao(Payment):
    def pay(self,money):
        print(余额宝支付了%s元 %money)


class PaymentFactory:
    ‘‘‘工厂类:封装了对象创建的细节‘‘‘
    def create_payment(self,method):
        if method ==alipay:
            return Alipay()
        elif method ==applepay:
            return Applepay()
        elif method ==yuebao:
            return Yuebao()
        else:
            return NameError(method)

factory = PaymentFactory()
alipay=factory.create_payment(yuebao)
alipay.pay(100)
  • 工厂方法模式
一、内容

定义一个用于创建对象的接口(工厂接口),让子类决定实例化哪一个产品类

二、角色

抽象工厂角色(Creator)
具体工厂角色(Concrere Creator)
抽象产品角色(Product)
具体产品角色(Concrete Product)
工厂方法模式相比简单工厂模式将每个具体产品都对应一个具体工厂

三、优点

每个具体产品都对应一个具体工厂类,不需要修改工厂类代码
隐藏了对象创建的实现细节
四、缺点 每增加一个具体产品类,就必须增加一个相应的具体工厂类
五、使用场景 需要生产多种、大量复杂对象的时候 需要降低耦合度的时候 当系统的产品种类需要经常扩展的时候
from abc import ABCMeta,abstractmethod
class PaymentFactory(metaclass=ABCMeta):
    @abstractmethod
    def create_payment(self):
        pass

class Payment(metaclass=ABCMeta):
    @abstractmethod
    def pay(self,money):
        pass

class Alipay(Payment):
    def pay(self, money):
        print(支付宝支付了%s元%money)

class Applepay(Payment):
    def pay(self, money):
        print(微信支付了%s元 %money)

class AlipayFactory(PaymentFactory):
    def create_payment(self):
        return Alipay()

class AppleFactory(PaymentFactory):
    def create_payment(self):
        return Applepay()

apple = AppleFactory()
apple.create_payment().pay(100)

alipay = AlipayFactory()
alipay.create_payment().pay(300)

#输出
# 微信支付了100元
# 支付宝支付了300元
  • 抽象工厂模式
一、内容

定义一个工厂类接口,当工厂子类来创建一系列相关或相互依赖的对象

例:生产一部手机,需要手机壳、CPU、操作系统三类对象进行组装,其中每类对象都有不同的种类。对每个具体工厂,分别生产一部手机所需要的三个对象。

二、角色

抽象工厂角色(Creator)
具体工厂角色(Concrete Creator)
抽象产品角色(Product)
具体产品角色(Concrete Product)
客户端(Client)
相比工厂方法模式,抽象工厂模式中的每个具体工厂都产生一套产品

三、优点

将客户端与类的具体实现相分离
每个工厂创建了一个完整的产品系列,使得易于交换产品系列
有利于产品的一致性(即产品之间的约束关系)
四、缺点 难以支持新种类的(抽象)产品
五、使用场景 系统要独立于产品的创建与组合时 强调一系列相关的产品对象的设计以便进行联合使用时 提供一个产品类库,想隐藏产品的具体实现时
from abc import abstractmethod,ABCMeta

#==============抽象产品============
class PhoneShell(metaclass=ABCMeta):
    ‘‘‘手机壳‘‘‘
    @abstractmethod
    def show_shell(self):
        pass

class CPU(metaclass=ABCMeta):
    ‘‘‘CPU‘‘‘
    @abstractmethod
    def show_cpu(self):
        pass

class OS(metaclass=ABCMeta):
    ‘‘‘操作系统‘‘‘
    @abstractmethod
    def show_os(self):
        pass


# ===============抽象工厂==============
class PhoneFactory(metaclass=ABCMeta):
    @abstractmethod
    def make_shell(self):
        ‘‘‘制作手机壳‘‘‘
        pass

    @abstractmethod
    def make_cpu(self):
        ‘‘‘制作cpu‘‘‘
        pass

    @abstractmethod
    def make_os(self):
        ‘‘‘制作手机壳‘‘‘
        pass


# =================具体产品==============
class SmallShell(PhoneShell):
    def show_shell(self):
        print(普通手机小手机壳)

class BigShell(PhoneShell):
    def show_shell(self):
        print(普通手机大手机壳)

class AppleShell(PhoneShell):
    def show_shell(self):
        print(苹果手机壳)

class YingTeerCPU(CPU):
    def show_cpu(self):
        print(英特尔cpu)

class MediaCPU(CPU):
    def show_cpu(self):
        print(联发科cpu)

class AppleCPU(CPU):
    def show_cpu(self):
        print(苹果cpu)

class Android(OS):
    def show_os(self):
        print(Android系统)

class IOS(OS):
    def show_os(self):
        print(ios系统)

# ==============具体工厂================
class MiFactory(PhoneFactory):
    def make_shell(self):
        return SmallShell()

    def make_cpu(self):
        return AppleCPU()

    def make_os(self):
        return Android()

class HuaWeiactory(PhoneFactory):
    def make_shell(self):
        return BigShell()

    def make_cpu(self):
        return YingTeerCPU()

    def make_os(self):
        return Android()

# ===============使用===============
class Phone:
    def __init__(self,cpu,os,shell):
        self.cpu = cpu
        self.os = os
        self.shell = shell

    def show_info(self):
        print(手机信息)
        self.cpu.show_cpu()
        self.os.show_os()
        self.shell.show_shell()

def make_phone(factory):
    cpu = factory.make_cpu()
    os = factory.make_os()
    shell = factory.make_shell()
    return Phone(cpu,os,shell)

p1 = make_phone(HuaWeiactory())
p1.show_info()

p2 = make_phone(MiFactory())
p2.show_info()
  • 创建者模式
一、内容

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

二、角色

抽象建造者
具体建造者
指挥者
产品
建造者模式与抽象工厂模式相似,也用来创建复杂对象。主要区别是建造者模式着重一步步构造一个复杂对象,而抽象工厂模式着重于多个系列的产品对象。

三、优点

隐藏了一个产品的内部结构和装配过程
将构造代码与表示代码分开
可以将构建过程进行更精细的控制
五、使用场景 当创建复杂对象的算法(Director)应该独立于该对象的组成部分以及它们的装配方式(Builder)时 当构造过程允许被构造的对象有不同的表示时(不同Builder)
import random
from abc import abstractmethod, ABCMeta

#------产品------

class Player:
    def __init__(self, face=None, body=None, arm=None, leg=None):
        self.face = face
        self.arm = arm
        self.leg = leg
        self.body = body

    def __str__(self):
        return "%s, %s, %s, %s" % (self.face, self.arm, self.body, self.leg)


#------建造者------


class PlayerBuilder(metaclass=ABCMeta):
    @abstractmethod
    def build_face(self):
        pass
    @abstractmethod
    def build_arm(self):
        pass
    @abstractmethod
    def build_leg(self):
        pass
    @abstractmethod
    def build_body(self):
        pass
    @abstractmethod
    def get_player(self):
        pass


class BeautifulWomanBuilder(PlayerBuilder):
    def __init__(self):
        self.player = Player()
    def build_face(self):
        self.player.face = "漂亮脸蛋"
    def build_arm(self):
        self.player.arm="细胳膊"
    def build_body(self):
        self.player.body="细腰"
    def build_leg(self):
        self.player.leg="长腿"
    def get_player(self):
        return self.player

class RandomPlayerBuilder(PlayerBuilder):
    def __init__(self):
        self.player = Player()
    def build_face(self):
        self.player.face = random.choice(["瓜子脸","西瓜子脸"])
    def build_arm(self):
        self.player.arm=random.choice(["长胳膊","短胳膊"])
    def build_body(self):
        self.player.body=random.choice(["苗条",""])
    def build_leg(self):
        self.player.leg=random.choice(["长腿","短腿"])
    def get_player(self):
        return self.player

class PlayerDirector:
    def __init__(self, builder):
        self.builder = builder
    # 控制组装顺序
    def build_player(self):
        self.builder.build_body()
        self.builder.build_face()
        self.builder.build_arm()
        self.builder.build_leg()
        return self.builder.get_player()




pd = PlayerDirector(RandomPlayerBuilder())
p = pd.build_player()
print(p)
  • 原型模式
  • 单例模式

总结创建型模式:

  依赖于继承的创建型模式:工厂方法模式

  依赖于组合的创建型模式:抽象工厂模式,创建者模式

二、什么是设计模式?

技术分享图片
每一个模式描述了一个在我们周围不断重复发生的问题,以及该问题的解决方案的核心。这样你就能一次又一次地使用该方案而不必做重复劳动。”

每一个设计模式系统地命名、解释和评价了面向对象系统中一个重要的和重复出现的设计。

GoF(Gang of Four)

设计模式四个基本要素:模式名称、问题、解决方案、效果

三、设计模式七大原则

1、开放封闭原则:一个软件实体如类,模块和函数应该对扩展是开放的,对修改是关闭的。即软件实体应尽量在不修改原有代码的情况下进行扩展(装饰器)

2、里氏替换原则:重写父类里面的方法,逻辑可能不一样,但是返回的结果参数啥的要一样(所有引用基类的地方必须能透明的使用其子类的对象)

3、依赖倒置原则:高层模块不应该依赖低层模块,二者都应该依赖其抽象,要针对接口编程,而不是针对实现编程。(接口类)

4、接口隔离原则:使用多个专门的接口,而不使用单一的总接口,即客户端不应该依赖那些它不需要实现的接口

5、迪米特法则:一个软件实体应当尽可能少的与其他实体发生相互作用

6、单一职责原则:一个类只负责一项职责(不要存在多于一个导致类变更的原因,即一个类只负责一项职责)

7、合同复用原则:多用组合少用继承

       一个类重用另一个类的代码有两种方式

  •  继承
  •  组合

a、下面来说一下接口隔离原则

技术分享图片
#假如说现在有这样的动物类
from abc import abstractmethod,ABCMeta   #借助abc模块来实现接口
#接口类就是为了提供标准,约束后面的子类

# class Animal(metaclass=ABCMeta):
#     @abstractmethod
#     def walk(self):
#         pass
#
#     @abstractmethod
#     def fly(self):
#         pass
#
#     @abstractmethod
#     def swim(self):
#         pass
#
# class Frog(Animal):
#     ‘‘‘像是这样定义一个青蛙类,由于接口类的方法都要被实现,而青蛙只会走,没不要要实现其他的方法
#     动物不同会的功能也会不同,所以这时候我们就可以选择用接口隔离原则
#     ‘‘‘
#     def walk(self):
#         print(‘青蛙会走‘)
#
# obj = Frog()
# obj.walk()   #会报错


# =====================改进-=================
class AnimalOnLand(metaclass=ABCMeta):
    ‘‘‘在陆地上的动物‘‘‘
    @abstractmethod
    def walk(self):
        pass

class AnimalInSky(metaclass=ABCMeta):
    ‘‘‘飞行动物‘‘‘
    @abstractmethod
    def fly(self):
        pass

class AnimalInWater(metaclass=ABCMeta):
    ‘‘‘在水里的动物‘‘‘
    @abstractmethod
    def swim(self):
        pass

class Tiger(AnimalOnLand):
    def walk(self):
        print(老虎在地上)

class Frog(AnimalOnLand,AnimalInWater):
    def swim(self):
        print(青蛙会游)

    def walk(self):
        print(会跳)

obj = Tiger()
obj.walk()

obj = Frog()
obj.walk()
obj.swim()
接口隔离原则

b、继承和组合

技术分享图片
# 合同复用原则:多用组合少用继承
class A:
    def test(self):
        return 你好啊

class B(A):  #继承
    def test(self):
        return 123

class C:
    def __init__(self):
        self.a = A()   #组合
        self.a.test()

    def test(self): 
        return 789

print(B().test())

print(C().a)
print(C().a.test())
print(C().test())
继承和组合示例

四、行为型模式:

  • 解释器模式
  • 责任链模式
一、内容

使多个对象都有机会处理请求,从而避免请求的发送者和接受者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求

直到有一个对象处理它为止

二、角色

抽象处理者
具体处理者
客户端
例:请假部门批准:项目主管----》部门经理----》总经理 

三、优点

降低耦合度:一个对象无需知道是其他哪一个对象处理其请求
四、缺点

请求不保证被接收:链的末端没有处理或者链配置错误
五、适用场景 有多个对象可以处理一个请求,哪个对象处理由时间运行时决定 在不明确接受者的情况下,向多个对象中的一个提交一个请求
技术分享图片
from abc import ABCMeta, abstractmethod
#
class Handler(metaclass=ABCMeta):
    @abstractmethod
    def handle_leave(self, day):
        pass


class GeneralManagerHandler(Handler):
    def handle_leave(self, day):
        if day < 10:
            print("总经理批准%d天假"%day)
        else:
            print("呵呵")


class DepartmentManagerHandler(Handler):
    def __init__(self):
        self.successor = GeneralManagerHandler()  #责任链的后面的一个人
    def handle_leave(self, day):
        if day < 7:
            print("部门经理批准%d天假"%day)
        else:
            print("部门经理无权准假")
            self.successor.handle_leave(day)


class ProjectDirectorHandler(Handler):
    def __init__(self):
        self.successor = DepartmentManagerHandler()
    def handle_leave(self, day):
        if day < 3:
            print("项目主管批准%d天假")
        else:
            print("项目主管无权准假")
            self.successor.handle_leave(day)


day = 4
h = ProjectDirectorHandler()
h.handle_leave(day)
请假示例
技术分享图片
#--高级例子--模仿js事件处理
# JavaScript中假如有三个嵌套的div,每个div绑定一个事件,就像冒泡一样,先找里面的,
# 如果里面有就是里面的事件,如果里面没有就找上一层的。以此类推
from abc import ABCMeta, abstractmethod
class Handler(metaclass=ABCMeta):
    @abstractmethod
    def add_event(self, func):
        pass

    @abstractmethod
    def handle(self):
        pass


class BodyHandler(Handler):
    def __init__(self):
        self.func = None

    def add_event(self, func):
        self.func = func

    def handle(self):
        if self.func:
            return self.func()
        else:
            print("已到最后一级,无法处理")


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

    def add_event(self, func):
        self.func = func

    def handle(self):
        if self.func:
            return self.func()
        else:
            return self.successor.handle()


# 客户端
# <body><div><a>

body = {type: body, name: body, children: [], father: None}

div = {type: div, name: div, children: [], father: body}

a = {type: a, name: a, children: [], father: div}

body[children].append(div)
div[children].append(a)

body[event_handler] = BodyHandler()
div[event_handler] = ElementHandler(div[father][event_handler])
a[event_handler] = ElementHandler(a[father][event_handler])


def attach_event(element, func):
    element[event_handler].add_event(func)

#test

def func_div():
    print("这是给div的函数")

def func_a():
    print("这是给a的函数")

def func_body():
    print("这是给body的函数")

# attach_event(div, func_div)
attach_event(a, func_a)
# attach_event(body, func_body)
a[event_handler].handle()
模仿js事件处理
  • 命令模式
  • 迭代器模式
  • 中介者模式
  • 备忘录模式
  • 观察者模式
  • 状态模式
  • 策略模式
  • 访问者模式
  • 模板方法模式

五、结构性模式:

  • 适配器模式
  • 桥模式
  • 组合模式
  • 装饰模式
  • 外观模式
  • 享元模式
  • 代理模式









以上是关于Python之设计模式的主要内容,如果未能解决你的问题,请参考以下文章

JUC并发编程 共享模式之工具 JUC CountdownLatch(倒计时锁) -- CountdownLatch应用(等待多个线程准备完毕( 可以覆盖上次的打印内)等待多个远程调用结束)(代码片段

炫酷 CSS 背景效果的 10 个代码片段

python之模块和包

python之模块和包

python RegEx模式片段

python调试之pdb调试工具