设计模式(GOF):
每一个设计模式系统地命名、解释和评价了面向对象系统中一个重要的和重复出现的设计
设计模式四个基本要素:模式名称、问题、解决方法、效果
设计模式前戏:
对象/类
封装、继承、多态
接口:一个特殊的类,声明了若干方法,要求继承该接口的类必须实现这些方法
作用:限制继承接口的类的方法的名称及调用方式;隐藏了类的内部实现
接口就是一种抽象的基类(父类),限制继承它的类必须实现接口中定义的某些方法
Python中接口的两种写法
1 class Interface: 2 def method(self,arg): 3 raise NotImplementedError 4 5 #抽象类不可以实例化 6 from abc import abstractmethod,ABCMeta 7 class Interface(metaclass=ABCMeta): 8 @abstractmethod 9 def method(self,arg): 10 pass
设计模式六大原则
开闭原则:一个软件实体如类、模块和函数应该对扩展开放,对修改关闭。即软件实体应尽量在不修改原有代码的情况下进行扩展。
里氏(Liskov)替换原则:所有引用基类(父类)的方法必须能透明地使用其子类的对象。
依赖倒置原则:高层模块不应该依赖低层模块,二者都应该依赖其抽象;抽象不应该依赖细节;细节应该依赖抽象。换言之,要针对接口编程,而不是针对实现编程。
接口隔离原则:使用多个专门的接口,而不使用单一的总接口,即客户端不应该依赖那些它不需要的接口。
迪米特法则:一个软件实体应当尽可能少地与其他实体发生相互作用(解耦)。
单一职责原则:不要存在多于一个导致类变更的原因。通俗的说,即一个类只负责一项职责。
创建型模式:工厂方法模式,抽象工厂模式,创建者模式,原型模式,单例模式
结构型模式:适配器模式,桥模式,组合模式,装饰模式,外观模式,享元模式,代理模式
行为型模式:解释器模式,责任链模式,命令模式,迭代器模式,中介者模式,备忘录模式,观察者模式,状态模式,策略模式,访问者模式,模板方法模式
单例模式:
内容:保证一个类只有一个实例,并提供一个访问它的全局访问点。
角色:单例(Singleton)
适用场景:当类只能有一个实例而且客户可以从一个众所周知的访问点访问它时
优点:对唯一实例的受控访问,单例相当于全局变量,但防止了命名空间被污染。
与单例模式功能相似的概念:全局变量、静态变量(方法)
例子:
#单例模式
1 #单例模式 2 #方法1 模块导入 3 # site=ExtraAppSite() 4 5 #方法2类方法 6 # class Foo(): 7 # _instance=None 8 # def __init__(self): 9 # pass 10 # @classmethod 11 # def get_instance(cls): 12 # if cls._instance: 13 # return cls._instance 14 # else: 15 # obj=cls() 16 # cls._instance=obj 17 # return obj 18 # a1=Foo.get_instance() 19 20 #方法3__new__ 21 # class Foo(): 22 # _instance=None 23 # def __init__(self): 24 # pass 25 # 26 # def __new__(cls, *args, **kwargs): #创建对象 27 # if cls._instance: 28 # return cls._instance 29 # else: 30 # obj=object.__new__(cls, *args, **kwargs) #创建出来的对象传给init self里面 31 # cls._instance=obj 32 # return obj 33 # 34 # #用户行为不需要改变 35 # obj=Foo() 36 # obj1=Foo() 37 # print(obj) 38 # print(obj1) 39 40 #单例模式的用处 41 # 自定义CURD组件时,没有必要创建多个实例来浪费空间 42 # 发布文章,对于特殊字符的过滤KindEditor 43 # class Kind(): 44 # def __init__(self): 45 # self.valid_tags=[ 46 # "a","div","h1" 47 # ] 48 # def valid(self,content): 49 # pass 50 # obj=Kind() 51 # body=obj.valid("<html>")
简单工厂模式
内容:不直接向客户端暴露对象创建的实现细节,而是通过一个工厂类来负责创建产品类的实例。
角色:工厂角色(Creator),抽象产品角色(Product),具体产品角色(Concrete Product)
优点:隐藏了对象创建的实现细节,客户端不需要修改代码
缺点:违反了单一职责原则,将创建逻辑集中到一个工厂类里、当添加新产品时,需要修改工厂类代码,违反了开闭原则
例子:
1 from abc import abstractmethod,ABCMeta 2 class Payment(metaclass=ABCMeta): 3 @abstractmethod 4 def pay(self,money): 5 pass 6 7 class Alipay(Payment): 8 def __init__(self,enable_yuebao=False): 9 self.enable_yuebao=enable_yuebao 10 11 def pay(self,money): 12 if self.enable_yuebao: 13 print('余额宝支付%s元'%money) 14 else: 15 print('支付宝支付%s元'%money) 16 17 class ApplePay(Payment): 18 def pay(self,money): 19 print('余额宝支付%s元'%money) 20 21 22 class PaymentFactory: 23 def create_payment(self,method): 24 if method=='alipay': 25 return Alipay() 26 elif method=='yuhebao': 27 return Alipay(enable_yuebao=True) 28 elif method=='applepay': 29 return ApplePay() 30 else: 31 raise NameError(method) 32 33 f=PaymentFactory() 34 p=f.create_payment('alipay') 35 p.pay(100)
工厂方法模式
内容:定义一个用于创建对象的接口(工厂接口),让子类决定实例化哪一个产品类。
角色:抽象工厂角色(Creator),具体工厂角色(Concrete Creator),抽象产品角色(Product),具体产品角色(Concrete Product)
工厂方法模式相比简单工厂模式将对每个具体产品都对应了一个具体工厂
实用场景:需要生产多种、大量复杂对象的时候、需要降低耦合度的时候、当系统中的产品种类需要经常扩展的时候。
优点:每个具体产品都对应一个具体工厂类,不需要修改工厂类代码、隐藏了对象创建的实现细节
缺点:每增加一个具体产品类,就必须增加一个相应的具体工厂类。
例子:
1 from abc import abstractmethod,ABCMeta 2 class Payment(metaclass=ABCMeta): 3 @abstractmethod 4 def pay(self, money): 5 pass 6 7 class Alipay(Payment): 8 def pay(self, money): 9 print('余额宝支付%s元' % money) 10 11 class ApplePay(Payment): 12 def pay(self, money): 13 print('余额宝支付%s元' % money) 14 15 16 class PaymentFactory(metaclass=ABCMeta): 17 @abstractmethod 18 def create_payment(self): 19 pass 20 21 22 class AlipayFactory(PaymentFactory): 23 def create_payment(self): 24 return Alipay() 25 26 class ApplePayFactory(PaymentFactory): 27 def create_payment(self): 28 return ApplePay() 29 30 31 af=AlipayFactory() 32 ali=af.create_payment() 33 ali.pay(120)
抽象工厂模式
内容:定义一个工厂类接口,让工厂子类来创建一系列相关或相互依赖的对象。
例:生产一部手机,需要手机壳,CPU,操作系统三类对象进行组装,其中每类对象都有不同的种类。对每个具体工厂,分别生产一部手机所需要的三个对象。
角色:抽象工厂角色(Creator),具体工厂角色(Concrete Creator),抽象产品角色(Product),具体产品角色(Product),客户端(Client)
相比工厂方法模式,抽象工厂模式中的每个具体工厂都生产一套产品。
适用场景:系统要独立于产品创建与组合时、强调一系列相关的产品对象的设计以便进行联合使用时、提供一个产品类库,想隐藏产品的具体实现时。
优点:将客户端与类具体实现相分离、每个工厂创建一个完整的产品系列,使得易于交换产品系列、有利于产品的一致性(即产品之间的约束关系)
缺点:难以支持新种类的(抽象)产品
例子:
1 from abc import abstractmethod,ABCMeta 2 3 #抽象工厂 4 class PhoneFactory(metaclass=ABCMeta): 5 @abstractmethod 6 def make_shell(self): 7 pass 8 9 @abstractmethod 10 def make_cpu(self): 11 pass 12 13 @abstractmethod 14 def make_os(self): 15 pass 16 17 #抽象产品 18 class PhoneShell(metaclass=ABCMeta): 19 @abstractmethod 20 def show_shell(self): 21 pass 22 23 class OS(metaclass=ABCMeta): 24 @abstractmethod 25 def show_os(self): 26 pass 27 28 class CPU(metaclass=ABCMeta): 29 @abstractmethod 30 def show_cpu(self): 31 pass 32 33 34 #具体产品 35 class SmallShell(PhoneShell): 36 def show_shell(self): 37 print('普通手机小手机壳') 38 39 class BigShell(PhoneShell): 40 def show_shell(self): 41 print('普通手机大手机壳') 42 43 class AppleShell(PhoneShell): 44 def show_shell(self): 45 print('苹果手机壳') 46 47 class SnapDragonCPU(CPU): 48 def show_cpu(self): 49 print('骁龙CPU') 50 51 class MediaTekCPU(CPU): 52 def show_cpu(self): 53 print('联发科CPU') 54 55 class AppleCPU(CPU): 56 def show_cpu(self): 57 print('苹果CPU') 58 59 class Android(OS): 60 def show_os(self): 61 print('Android系统') 62 63 class IOS(OS): 64 def show_os(self): 65 print('iOS系统') 66 67 #具体工厂 68 class MiFactory(PhoneFactory): 69 def make_cpu(self): 70 return SnapDragonCPU() 71 72 def make_os(self): 73 return Android() 74 75 def make_shell(self): 76 return BigShell() 77 78 79 class HuaweiFactory(PhoneFactory): 80 def make_cpu(self): 81 return MediaTekCPU() 82 83 def make_os(self): 84 return Android() 85 86 def make_shell(self): 87 return SmallShell() 88 89 class IPhoneFactory(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 class Phone: 101 def __init__(self,cpu,os,shell): 102 self.cpu=cpu 103 self.os=os 104 self.shell=shell 105 106 def show_info(self): 107 print('手机信息:') 108 self.cpu.show_cpu() 109 self.os.show_os() 110 self.shell.show_shell() 111 112 def make_phone(factory): 113 cpu=factory.make_cpu() 114 os=factory.make_os() 115 shell=factory.make_shell() 116 return Phone(cpu,os,shell) 117 118 pl=make_phone(IPhoneFactory()) 119 pl.show_info()
建造者模式
内容:将一个复杂对象的构建与它表示分离,使得同样的构建过程可以创建不同的表示。
角色:抽象建造者(Builder),具体建造者(Concrete Builder),指挥者(Director),产品(Product)
建造者模式与抽象工厂模式相似,也用来创建复杂对象。主要区别是建造者模式着重一步步构造一个复杂对象,而抽象工厂模式着重于多个系列产品对象。
适用场景:当创建复杂对象的算法(Director)应该独立于该对象的组成部分时,当构造过程允许被构造的对象有不同的表示时(不同Builder)。
优点:隐藏了一个产品的内部结构和装配过程、将构造代码与表示代码分开、可以对构造过程进行更精细的控制
例子:
1 from abc import abstractmethod,ABCMeta 2 class Player: 3 def __init__(self,face=None,body=None,arm=None,leg=None): 4 self.face=face 5 self.body=body 6 self.arm=arm 7 self.leg=leg 8 9 def __str__(self): 10 return "%s,%s,%s,%s"%(self.face,self.arm,self.body,self.leg) 11 12 #建造者 13 class PlayerBuilder(metaclass=ABCMeta): 14 @abstractmethod 15 def build_face(self): 16 pass 17 18 @abstractmethod 19 def build_arm(self): 20 pass 21 22 @abstractmethod 23 def build_leg(self): 24 pass 25 26 @abstractmethod 27 def build_body(self): 28 pass 29 30 @abstractmethod 31 def get_player(self): 32 pass 33 34 class BeautifulWomanBuilder(PlayerBuilder): 35 def __init__(self): 36 self.player=Player() 37 38 def build_face(self): 39 self.player.face='漂亮脸蛋' 40 41 def build_arm(self): 42 self.player.arm='细胳膊' 43 44 def build_leg(self): 45 self.player.leg = '长腿' 46 47 def build_body(self): 48 self.player.body = '细腰' 49 50 def get_player(self): 51 return self.player 52 53 54 class PlayDirector: 55 def build_player(self,builder): 56 builder.build_body() 57 builder.build_arm() 58 builder.build_leg() 59 builder.build_face() 60 return builder.get_player() 61 62 director=PlayDirector() 63 builder=BeautifulWomanBuilder() 64 p=director.build_player(builder) 65 print(p)
创建型模型小结
使用Abstract Factory、Prototype或Builder的设计甚至比使用Factory Method的那些设计更灵活,但它们也更加复杂。通常,设计以使用Factory Method开始,并且当设计者发现需要更大的灵活性时,设计便会向其他创建模式演化。当你在设计标准之间进行权衡的时候,了解多个模式可以给你提供更多的选择余地。
依赖于继承的创建型模式:工厂方法模式
依赖于组合的创建型模式:抽象工厂模式、创建者模式