Python之设计模式

一、设计模式分类

a、创建型模式

  • 简单工厂模式

    一、内容 不直接向客户端暴露对象创建的实现细节,而是通过一个工厂类来负责创建产品类的实例。

    二、角色

    工厂角色(Creator) 抽象产品角色(Product) 具体产品角色(Concrete Product) 三、优点

    隐藏了对象创建的实现细节 客户端不需要修改代码 四、缺点

    违反了单一职责原则,将创建逻辑集中到一个工厂类中 当添加新产品时,需要修改工厂类代码,违反了开放封闭原则

代码实例:

1from abc import abstractmethod,ABCMeta 2class Payment(metaclass=ABCMeta): 3 @abstractmethod 4 def pay(self): 5 pass 6 7class Alipay(Payment): 8 def __init__(self,money): 9 self.money = money 10 11 def pay(self): 12 print('支付宝支付了%s元'%self.money) 13 14class Whatpay(Payment): 15 def __init__(self, money): 16 self.money = money 17 18 def pay(self): 19 print('微信支付了%s元' % self.money) 20 21 22obj = Alipay(100) 23obj.pay() 24 25obj2 = Whatpay(200) 26obj2.pay()

初始的

1from abc import abstractmethod,ABCMeta 2class Payment(metaclass=ABCMeta): 3 @abstractmethod 4 def pay(self,money): 5 pass 6 7class Alipay(Payment): 8 def pay(self, money): 9 print('支付宝支付了%s元'%money) 10 11class Applepay(Payment): 12 def pay(self, money): 13 print('微信支付了%s元' %money) 14 15class Yuebao(Payment): 16 def pay(self,money): 17 print('余额宝支付了%s元' %money) 18 19 20class PaymentFactory: 21 '''工厂类:封装了对象创建的细节''' 22 def create_payment(self,method): 23 if method =='alipay': 24 return Alipay() 25 elif method =='applepay': 26 return Applepay() 27 elif method =='yuebao': 28 return Yuebao() 29 else: 30 return NameError(method) 31 32factory = PaymentFactory() 33alipay=factory.create_payment('yuebao') 34alipay.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

    1@abstractmethod 2def make_cpu(self): 3 '''制作cpu''' 4 pass 5 6@abstractmethod 7def make_os(self): 8 '''制作手机壳''' 9 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()

    1def make_cpu(self): 2 return AppleCPU() 3 4def make_os(self): 5 return Android()

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

    1def make_cpu(self): 2 return YingTeerCPU() 3 4def make_os(self): 5 return Android()

    ===============使用===============

    class Phone: def init(self,cpu,os,shell): self.cpu = cpu self.os = os self.shell = shell

    1def show_info(self): 2 print('手机信息') 3 self.cpu.show_cpu() 4 self.os.show_os() 5 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

    1def __str__(self): 2 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)

  • 原型模式

  • 单例模式

总结创建型模式:

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

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

二、什么是设计模式?

复制代码

1每一个模式描述了一个在我们周围不断重复发生的问题,以及该问题的解决方案的核心。这样你就能一次又一次地使用该方案而不必做重复劳动。” 2 3每一个设计模式系统地命名、解释和评价了面向对象系统中一个重要的和重复出现的设计。 4 5GoF(Gang of Four) 6 7设计模式四个基本要素:模式名称、问题、解决方案、效果

三、设计模式七大原则

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

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

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

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

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

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

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

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

  •  继承
  •  组合

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

1#假如说现在有这样的动物类 2from abc import abstractmethod,ABCMeta #借助abc模块来实现接口 3#接口类就是为了提供标准,约束后面的子类 4 5# class Animal(metaclass=ABCMeta): 6# @abstractmethod 7# def walk(self): 8# pass 9# 10# @abstractmethod 11# def fly(self): 12# pass 13# 14# @abstractmethod 15# def swim(self): 16# pass 17# 18# class Frog(Animal): 19# '''像是这样定义一个青蛙类,由于接口类的方法都要被实现,而青蛙只会走,没不要要实现其他的方法 20# 动物不同会的功能也会不同,所以这时候我们就可以选择用接口隔离原则 21# ''' 22# def walk(self): 23# print('青蛙会走') 24# 25# obj = Frog() 26# obj.walk() #会报错 27 28 29# =====================改进-================= 30class AnimalOnLand(metaclass=ABCMeta): 31 '''在陆地上的动物''' 32 @abstractmethod 33 def walk(self): 34 pass 35 36class AnimalInSky(metaclass=ABCMeta): 37 '''飞行动物''' 38 @abstractmethod 39 def fly(self): 40 pass 41 42class AnimalInWater(metaclass=ABCMeta): 43 '''在水里的动物''' 44 @abstractmethod 45 def swim(self): 46 pass 47 48class Tiger(AnimalOnLand): 49 def walk(self): 50 print('老虎在地上') 51 52class Frog(AnimalOnLand,AnimalInWater): 53 def swim(self): 54 print('青蛙会游') 55 56 def walk(self): 57 print('会跳') 58 59obj = Tiger() 60obj.walk() 61 62obj = Frog() 63obj.walk() 64obj.swim()

接口隔离原则

b、继承和组合

1# 合同复用原则:多用组合少用继承 2class A: 3 def test(self): 4 return '你好啊' 5 6class B(A): #继承 7 def test(self): 8 return 123 9 10class C: 11 def __init__(self): 12 self.a = A() #组合 13 self.a.test() 14 15 def test(self): 16 return 789 17 18print(B().test()) 19 20print(C().a) 21print(C().a.test()) 22print(C().test())

继承和组合示例

四、行为型模式:

  • 解释器模式

  • 责任链模式

    一、内容

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

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

    二、角色

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

    三、优点

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

    请求不保证被接收:链的末端没有处理或者链配置错误 五、适用场景

    有多个对象可以处理一个请求,哪个对象处理由时间运行时决定 在不明确接受者的情况下,向多个对象中的一个提交一个请求

1from abc import ABCMeta, abstractmethod 2# 3class Handler(metaclass=ABCMeta): 4 @abstractmethod 5 def handle_leave(self, day): 6 pass 7 8 9class GeneralManagerHandler(Handler): 10 def handle_leave(self, day): 11 if day < 10: 12 print("总经理批准%d天假"%day) 13 else: 14 print("呵呵") 15 16 17class DepartmentManagerHandler(Handler): 18 def __init__(self): 19 self.successor = GeneralManagerHandler() #责任链的后面的一个人 20 def handle_leave(self, day): 21 if day < 7: 22 print("部门经理批准%d天假"%day) 23 else: 24 print("部门经理无权准假") 25 self.successor.handle_leave(day) 26 27 28class ProjectDirectorHandler(Handler): 29 def __init__(self): 30 self.successor = DepartmentManagerHandler() 31 def handle_leave(self, day): 32 if day < 3: 33 print("项目主管批准%d天假") 34 else: 35 print("项目主管无权准假") 36 self.successor.handle_leave(day) 37 38 39day = 4 40h = ProjectDirectorHandler() 41h.handle_leave(day)

请假示例

1#--高级例子--模仿js事件处理 2# JavaScript中假如有三个嵌套的div,每个div绑定一个事件,就像冒泡一样,先找里面的, 3# 如果里面有就是里面的事件,如果里面没有就找上一层的。以此类推 4from abc import ABCMeta, abstractmethod 5class Handler(metaclass=ABCMeta): 6 @abstractmethod 7 def add_event(self, func): 8 pass 9 10 @abstractmethod 11 def handle(self): 12 pass 13 14 15class BodyHandler(Handler): 16 def __init__(self): 17 self.func = None 18 19 def add_event(self, func): 20 self.func = func 21 22 def handle(self): 23 if self.func: 24 return self.func() 25 else: 26 print("已到最后一级,无法处理") 27 28 29class ElementHandler(Handler): 30 def __init__(self, successor): 31 self.func = None 32 self.successor = successor 33 34 def add_event(self, func): 35 self.func = func 36 37 def handle(self): 38 if self.func: 39 return self.func() 40 else: 41 return self.successor.handle() 42 43 44# 客户端 45# <body><div><a> 46 47body = {'type': 'body', 'name': 'body', 'children': [], 'father': None} 48 49div = {'type': 'div', 'name': 'div', 'children': [], 'father': body} 50 51a = {'type': 'a', 'name': 'a', 'children': [], 'father': div} 52 53body['children'].append(div) 54div['children'].append(a) 55 56body['event_handler'] = BodyHandler() 57div['event_handler'] = ElementHandler(div['father']['event_handler']) 58a['event_handler'] = ElementHandler(a['father']['event_handler']) 59 60 61def attach_event(element, func): 62 element['event_handler'].add_event(func) 63 64#test 65 66def func_div(): 67 print("这是给div的函数") 68 69def func_a(): 70 print("这是给a的函数") 71 72def func_body(): 73 print("这是给body的函数") 74 75# attach_event(div, func_div) 76attach_event(a, func_a) 77# attach_event(body, func_body) 78a['event_handler'].handle()

模仿js事件处理

  • 命令模式
  • 迭代器模式
  • 中介者模式
  • 备忘录模式
  • 观察者模式
  • 状态模式
  • 策略模式
  • 访问者模式
  • 模板方法模式

五、结构性模式:

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

评论区

加载中...

相关推荐

MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1

文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

MySQL部分从库上面因为大量的临时表tmp_table造成慢查询

背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_

皕杰报表之UUID

​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为

手写Java HashMap源码

HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22

2020年前端实用代码段,为你的工作保驾护航

有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )