设计模式
解决不断重复问题的方案,而这个方案之后就可以一次又一次的不断重复的使用
设计模式分类
创建型模式:对对象创建会消耗系统的很多的资源,单独对对象的创建进行研究
- 简单工厂模式(Simple Factory)
- 工厂方法模式(Factory Method)
- 抽象工厂模式(Abstract Factory)
- 创建者模式(Builder)
- 原型模式(Prototype)
- 单例模式(Singleton)
结构型模式:对对象的结构、继承、依赖关系设计,这些会影响到后续程序的维护性、代码的健壮性、耦合性等
- 外观模式(Facade)
- 适配器模式(Adapter)
- 代理模式(Proxy)
- 装饰模式(Decorator)
- 桥模式(Bridge)
- 组合模式(Composite)
- 享元模式(Flyweight)
行为性模式:对对象的行为设计的好的话,对象的行为就会更清晰,它们之间的协作效率就会提高
- 模板方法模式(Template Method)
- 观察者模式(Observer)
- 状态模式(State)
- 策略模式(Strategy)
- 职责链模式(Chain of Responsibility)
- 命令模式(Command)
- 访问者模式(Visitor)
- 调停者模式(Mediator)
- 备忘录模式(Memento)
- 迭代器模式(Iterator)
- 解释器模式(Interpreter)
原则
开闭原则:只能加代码,但是不能修改
里氏替换原则:引用父类的地方必须能透明地使用其子类的对象
依赖倒置原则:针对接口编程,而不是针对实现编程
接口隔离原则:使用多个专门的接口,不使用总的单一接口
多继承存在一个问题:钻石继承问题 A类是B.C类,D类也继承B.C类 A类就不知道从哪里继承来的
迪米特原则:简单的说就是降低耦合
单一职责:一个类只负责一个职责
接口说明
当我们继承,继承父类时候,必须实现某个方法
当我们使用from abc import ABCMeta, abstractmethod虚类也是实现某个抽象方法
简单工厂模式
使用场景:
当类不知道它所必须创建的对象类的时候
当一个类希望由它的子类来指定它所创建的对象的时候
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 4 from abc import ABCMeta, abstractmethod 5 6 7 class Payment(metaclass=ABCMeta): 8 """抽象产品角色""" 9 10 @abstractmethod 11 def pay(self, money): 12 raise NotImplementedError 13 14 15 class AliPay(Payment): 16 """具体产品角色""" 17 18 def pay(self, money): 19 print("支付宝支付%s元" % money) 20 21 22 class ApplePay(Payment): 23 """具体产品角色""" 24 25 def pay(self, money): 26 print("苹果支付%s" % money) 27 28 29 class PaymentFactory: 30 """工厂角色""" 31 32 def create_payment(self, method): 33 if method == "ApplePay": 34 return ApplePay() 35 elif method == "AliPay": 36 return AliPay() 37 else: 38 raise NameError(method) 39 40 41 pf = PaymentFactory() 42 p = pf.create_payment("ApplePay") 43 p.pay(100)
总结:使用简单工厂模式时候,首先要定义一个抽象产品类,其次要实现具体的产品类,最后实现工厂类
优点:隐藏了对象创建的实现细节,客服端不需要修改代码
缺点:违反了单一职责原则,将创建逻辑几种到工厂类里
当添加新产品时候,需要修改工厂代码,违反开闭原则
工厂方法设计模式
定义一个工厂接口,然后具体到某一个工厂
使用场景:
需要生产多种大量复杂对象的时候,需要降低耦合度的,系统需要经常扩展的情况下
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 4 from abc import ABCMeta, abstractmethod 5 6 7 class Payment(metaclass=ABCMeta): 8 """抽象产品角色""" 9 10 @abstractmethod 11 def pay(self, money): 12 raise NotImplementedError 13 14 15 class AliPay(Payment): 16 """具体产品角色""" 17 18 def __init__(self, use_huabei=False): 19 self.use_huabei = use_huabei 20 21 def pay(self, money): 22 if self.use_huabei: 23 print("花呗支付%s元" % money) 24 else: 25 print("支付宝支付%s元" % money) 26 27 28 class ApplePay(Payment): 29 """具体产品角色""" 30 31 def pay(self, money): 32 print("苹果支付%s" % money) 33 34 35 class PaymentFactory(metaclass=ABCMeta): 36 """抽象工厂角色""" 37 38 @abstractmethod 39 def create_payment(self): 40 pass 41 42 43 class AliPayFactory(PaymentFactory): 44 """具体工厂角色""" 45 46 def create_payment(self): 47 return AliPay() 48 49 50 class ApplePayFactory(PaymentFactory): 51 def create_payment(self): 52 return ApplePay() 53 54 55 class HuaBeiFactory(PaymentFactory): 56 def create_payment(self): 57 return AliPay(use_huabei=True) 58 59 60 af = AliPayFactory() 61 ali = af.create_payment() 62 ali.pay(120) 63 64 af1 = HuaBeiFactory() 65 ali1 = af1.create_payment() 66 ali1.pay(120)
总结:要使用工厂方法设计模式时候,要实现抽象产品类,具体产品类,抽象工厂类,具体工厂类
优点:不需要修改工厂类代码,隐藏对象的实现细节
缺点:每增加一个具体产品,都需要加一个相应的具体工厂类
抽象工厂模式
使用场景:
系统要独立于产品的创建于组合(着重组合)
强调一系列相关的产品对象的设计以便进行联合使用
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 4 from abc import abstractmethod, ABCMeta 5 6 7 # -------抽象产品--------- 8 class PhoneShell(metaclass=ABCMeta): 9 @abstractmethod 10 def show_shell(self): 11 pass 12 13 14 class CPU(metaclass=ABCMeta): 15 @abstractmethod 16 def show_cpu(self): 17 pass 18 19 20 class OS(metaclass=ABCMeta): 21 @abstractmethod 22 def show_os(self): 23 pass 24 25 26 # ------------------抽象工厂------------------- 27 class PhoneFactory(metaclass=ABCMeta): 28 @abstractmethod 29 def make_shell(self): 30 pass 31 32 @abstractmethod 33 def make_cpu(self): 34 pass 35 36 @abstractmethod 37 def make_os(self): 38 pass 39 40 41 # ----------------具体产品-------------- 42 class SmallShell(PhoneShell): 43 def show_shell(self): 44 print("普通的小手机壳") 45 46 47 class BigShell(PhoneShell): 48 def show_shell(self): 49 print("普通的大手机壳") 50 51 52 class AppleShell(PhoneShell): 53 def show_shell(self): 54 print("苹果手机壳") 55 56 57 class AppleCPU(CPU): 58 def show_cpu(self): 59 print("苹果cpu") 60 61 62 class SnapDragonCPU(CPU): 63 def show_cpu(self): 64 print("骁龙cpu") 65 66 67 class IOS(OS): 68 def show_os(self): 69 print("ios系统") 70 71 72 class Android(OS): 73 def show_os(self): 74 print("安卓系统") 75 76 77 # -----------------具体工厂------------- 78 class MiFactory(PhoneFactory): 79 def make_cpu(self): 80 return SnapDragonCPU() 81 82 def make_os(self): 83 return Android() 84 85 def make_shell(self): 86 return BigShell() 87 88 89 class AppleFactory(PhoneFactory): 90 def make_cpu(self): 91 return AppleCPU() 92 93 def make_os(self): 94 return IOS() 95 96 def make_shell(self): 97 return AppleShell() 98 99 100 # ----------------客服端---------------- 101 class Phone: 102 def __init__(self, cpu, os, shell): 103 self.cpu = cpu 104 self.os = os 105 self.shell = shell 106 107 def show_info(self): 108 print("手机信息是:") 109 self.cpu.show_cpu() 110 self.os.show_os() 111 self.shell.show_shell() 112 113 114 def make_phone(factory): 115 cpu = factory.make_cpu() 116 os = factory.make_os() 117 shell = factory.make_shell() 118 return Phone(cpu, os, shell) 119 120 121 p1 = make_phone(AppleFactory()) 122 p1.show_info() 123 124 """ 125 手机信息是: 126 苹果cpu 127 ios系统 128 苹果手机壳 129 """
总结:要使用抽象工厂模式的时候,要实现抽象产品,抽象工厂,具体产品,具体工厂,客服端
优点:将客服端与类的具体实现相分离
每个工厂创建了一个完整的产品系列
有利于产品的一致性(产品之间的约束关系)
缺点:难以支持新种类的(抽象)产品
建造者模式
内容:
将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
使用场景:
建造者模式着重一步步构造一个复杂对象,与上述抽象工厂模式对比它着重多个系列的产品对象
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 4 from abc import abstractmethod, ABCMeta 5 6 7 # -------------------产品-------------------- 8 class Player: 9 def __init__(self, face=None, body=None, arm=None, leg=None): 10 self.face = face 11 self.arm = arm 12 self.leg = leg 13 self.body = body 14 15 def __str__(self): 16 return "%s, %s, %s, %s的猴子" % (self.face, self.arm, self.leg, self.body) 17 18 19 class PlayerBuilder(metaclass=ABCMeta): 20 @abstractmethod 21 def build_face(self): 22 pass 23 24 @abstractmethod 25 def build_arm(self): 26 pass 27 28 @abstractmethod 29 def build_leg(self): 30 pass 31 32 @abstractmethod 33 def build_body(self): 34 pass 35 36 @abstractmethod 37 def get_player(self): 38 pass 39 40 41 class BeautifulWomanBuilder(PlayerBuilder): 42 def __init__(self): 43 self.player = Player() 44 45 def build_face(self): 46 self.player.face = "脸蛋漂亮" 47 48 def build_arm(self): 49 self.player.arm = "细胳膊" 50 51 def build_body(self): 52 self.player.body = "细腰" 53 54 def build_leg(self): 55 self.player.leg = "大长腿" 56 57 def get_player(self): 58 return self.player 59 60 61 class PlayerDirector: 62 """指挥者""" 63 def build_player(self, builder): 64 builder.build_body() 65 builder.build_face() 66 builder.build_arm() 67 builder.build_leg() 68 return builder.get_player() 69 70 71 pd = PlayerDirector() 72 pb = BeautifulWomanBuilder() 73 p = pd.build_player(pb) 74 print(p)
总结:如果场景适合的情况下,需要创建抽象建造者类,具体建造者,指挥者,产品
优点:隐藏了一个产品的内部结构和装配过程
将构造代码与表示代码分开
可以对构造过程进行更精细的控制
单例模式
内容:保证一个类只有一个实例,并提供一个访问它的全局访问点
使用场景:当类只能有一个实例而且客服可以从一个众所周知的访问点访问(日志对象,数据库连接,文件对象,都要关闭才能连接,import,相似全局变量)
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 4 5 class Singleton(object): 6 def __new__(cls, *args, **kwargs): 7 if not hasattr(cls, "_instance"): 8 cls._instance = super(Singleton, cls).__new__(cls) 9 return cls._instance 10 11 12 class Myclass(Singleton): 13 def __init__(self, name=None): 14 if name is not None: 15 self.name = name 16 17 18 a = Myclass("a") 19 print(a) 20 print(a.name) 21 22 b = Myclass("b") 23 print(b) 24 print(b.name) 25 26 print(a) 27 print(a.name) 28 """ 29 <__main__.Myclass object at 0x000001FC1CBDFA20> 30 a 31 <__main__.Myclass object at 0x000001FC1CBDFA20> 32 b 33 <__main__.Myclass object at 0x000001FC1CBDFA20> 34 b 35 """
总结:
优点:对唯一实例的访问受控
代理模式
内容:为其它对象提供一种代理以控制对这个对象的访问
使用场景:远程代理:为远程的对象提供代理 虚代理:根据需要创建很大的对象省内存 保护代理:控制对原始对象的访问
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 4 """ 5 远程代理: 如果别的机器想用我的接口,我就要在本地实现一个socket连接类,煞笔250调用的时候先连接我再调用我的接口 6 虚代理:根据需要创建对象 比如手机省流量无图片模式的时候,它需要看图才给它创建 7 保护代理:存好的表数据对象,只能读不能写的时候 8 """ 9 from abc import ABCMeta, abstractmethod 10 11 12 class Subject(metaclass=ABCMeta): 13 @abstractmethod 14 def get_content(self): 15 raise NotImplementedError 16 17 18 class RealSubject(Subject): 19 def __init__(self, filename): 20 print('打开文件开始读取文件%s' % filename) 21 f = open(filename) 22 self.content = f.read() 23 f.close() 24 25 def get_content(self): 26 return self.content 27 28 29 class ProxyA(Subject): 30 def __init__(self, filename): 31 self.filename = filename 32 self.subj = None 33 34 def get_content(self): 35 if not self.subj: 36 self.subj = RealSubject(self.filename) 37 return self.subj.get_content() 38 39 40 p = ProxyA("abc.txt") # 根本没读取,只有调用get_content才去读,虚代理 41 print(p.get_content()) 42 43 # 还可以写保护代理 修改文件的时候如果没有权限就不能写
总结:场景适合的话要使用就要创建抽象实体类,具体实体类,代理类
优点:
保护:对对象有一些附加的操作达到对此对象的保护
虚:根据需要创建对象,节省内存
远程:为远程的对象提供代理,比如远程对象不能直接访问,我封装socket之后它连接上我才能访问
适配器模式
内容:能使得原来接口不兼容而不能一起工作的那些类可以一起工作。理解成月老,哈哈哈哈搭线
使用场景:接口不兼容
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 4 from abc import ABCMeta, abstractmethod 5 6 7 class Payment(metaclass=ABCMeta): 8 """抽象产品角色""" 9 10 @abstractmethod 11 def pay(self, money): 12 raise NotImplementedError 13 14 15 class AliPay(Payment): 16 """具体产品角色""" 17 18 def pay(self, money): 19 print("支付宝支付%s元" % money) 20 21 22 class ApplePay(Payment): 23 """具体产品角色""" 24 25 def pay(self, money): 26 print("苹果支付%s" % money) 27 28 29 class WechatPay: 30 def huaqian(self, money): 31 print("微信支付%s元" % money) 32 33 34 class BankPay: 35 def huaqian(self, money): 36 print("银联支付%s元" % money) 37 38 39 # 类适配器 40 class NewWechatPay(WechatPay, Payment): 41 def pay(self, money): 42 self.huaqian(money) 43 44 45 # 对象适配器 46 class PaymentAdapter(Payment): 47 def __init__(self, w): 48 self.payment = w # 对象 49 50 def pay(self, money): 51 self.payment.huaqian(120) 52 53 54 # p = NewWechatPay() 55 # p.pay(120) 56 57 p = PaymentAdapter(WechatPay()) 58 p.pay(120) 59 60 p = PaymentAdapter(BankPay()) 61 p.pay(120)
总结:如果在满足使用场景,要去使用抽象产品,具体产品不符合接口规范(待适配类),适配器类
实现两种方式:
类适配器:使用多继承
对象适配器:使用组合
持续更新中........