设计模式(GOF):
每一个设计模式系统地命名、解释和评价了面向对象系统中一个重要的和重复出现的设计
设计模式四个基本要素:模式名称、问题、解决方法、效果
设计模式前戏:
对象/类
封装、继承、多态
接口:一个特殊的类,声明了若干方法,要求继承该接口的类必须实现这些方法
作用:限制继承接口的类的方法的名称及调用方式;隐藏了类的内部实现
接口就是一种抽象的基类(父类),限制继承它的类必须实现接口中定义的某些方法
Python中接口的两种写法
1 classInterface:2 defmethod(self,arg):3 raiseNotImplementedError4
5 #抽象类不可以实例化
6 from abc importabstractmethod,ABCMeta7 class Interface(metaclass=ABCMeta):8 @abstractmethod9 defmethod(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("")
简单工厂模式
内容:不直接向客户端暴露对象创建的实现细节,而是通过一个工厂类来负责创建产品类的实例。
角色:工厂角色(Creator),抽象产品角色(Product),具体产品角色(Concrete Product)
优点:隐藏了对象创建的实现细节,客户端不需要修改代码
缺点:违反了单一职责原则,将创建逻辑集中到一个工厂类里、当添加新产品时,需要修改工厂类代码,违反了开闭原则
例子:
1 from abc importabstractmethod,ABCMeta2 class Payment(metaclass=ABCMeta):3 @abstractmethod4 defpay(self,money):5 pass
6
7 classAlipay(Payment):8 def __init__(self,enable_yuebao=False):9 self.enable_yuebao=enable_yuebao10
11 defpay(self,money):12 ifself.enable_yuebao:13 print('余额宝支付%s元'%money)14 else:15 print('支付宝支付%s元'%money)16
17 classApplePay(Payment):18 defpay(self,money):19 print('余额宝支付%s元'%money)20
21
22 classPaymentFactory:23 defcreate_payment(self,method):24 if method=='alipay':25 returnAlipay()26 elif method=='yuhebao':27 return Alipay(enable_yuebao=True)28 elif method=='applepay':29 returnApplePay()30 else:31 raiseNameError(method)32
33 f=PaymentFactory()34 p=f.create_payment('alipay')35 p.pay(100)
工厂方法模式
内容:定义一个用于创建对象的接口(工厂接口),让子类决定实例化哪一个产品类。
角色:抽象工厂角色(Creator),具体工厂角色(Concrete Creator),抽象产品角色(Product),具体产品角色(Concrete Product)
工厂方法模式相比简单工厂模式将对每个具体产品都对应了一个具体工厂
实用场景:需要生产多种、大量复杂对象的时候、需要降低耦合度的时候、当系统中的产品种类需要经常扩展的时候。
优点:每个具体产品都对应一个具体工厂类,不需要修改工厂类代码、隐藏了对象创建的实现细节
缺点:每增加一个具体产品类,就必须增加一个相应的具体工厂类。
例子:
1 from abc importabstractmethod,ABCMeta2 class Payment(metaclass=ABCMeta):3 @abstractmethod4 defpay(self, money):5 pass
6
7 classAlipay(Payment):8 defpay(self, money):9 print('余额宝支付%s元' %money)10
11 classApplePay(Payment):12 defpay(self, money):13 print('余额宝支付%s元' %money)14
15
16 class PaymentFactory(metaclass=ABCMeta):17 @abstractmethod18 defcreate_payment(self):19 pass
20
21
22 classAlipayFactory(PaymentFactory):23 defcreate_payment(self):24 returnAlipay()25
26 classApplePayFactory(PaymentFactory):27 defcreate_payment(self):28 returnApplePay()29
30
31 af=AlipayFactory()32 ali=af.create_payment()33 ali.pay(120)
抽象工厂模式
内容:定义一个工厂类接口,让工厂子类来创建一系列相关或相互依赖的对象。
例:生产一部手机,需要手机壳,CPU,操作系统三类对象进行组装,其中每类对象都有不同的种类。对每个具体工厂,分别生产一部手机所需要的三个对象。
角色:抽象工厂角色(Creator),具体工厂角色(Concrete Creator),抽象产品角色(Product),具体产品角色(Product),客户端(Client)
相比工厂方法模式,抽象工厂模式中的每个具体工厂都生产一套产品。
适用场景:系统要独立于产品创建与组合时、强调一系列相关的产品对象的设计以便进行联合使用时、提供一个产品类库,想隐藏产品的具体实现时。
优点:将客户端与类具体实现相分离、每个工厂创建一个完整的产品系列,使得易于交换产品系列、有利于产品的一致性(即产品之间的约束关系)
缺点:难以支持新种类的(抽象)产品
例子:
1 from abc importabstractmethod,ABCMeta2
3 #抽象工厂
4 class PhoneFactory(metaclass=ABCMeta):5 @abstractmethod6 defmake_shell(self):7 pass
8
9 @abstractmethod10 defmake_cpu(self):11 pass
12
13 @abstractmethod14 defmake_os(self):15 pass
16
17 #抽象产品
18 class PhoneShell(metaclass=ABCMeta):19 @abstractmethod20 defshow_shell(self):21 pass
22
23 class OS(metaclass=ABCMeta):24 @abstractmethod25 defshow_os(self):26 pass
27
28 class CPU(metaclass=ABCMeta):29 @abstractmethod30 defshow_cpu(self):31 pass
32
33
34 #具体产品
35 classSmallShell(PhoneShell):36 defshow_shell(self):37 print('普通手机小手机壳')38
39 classBigShell(PhoneShell):40 defshow_shell(self):41 print('普通手机大手机壳')42
43 classAppleShell(PhoneShell):44 defshow_shell(self):45 print('苹果手机壳')46
47 classSnapDragonCPU(CPU):48 defshow_cpu(self):49 print('骁龙CPU')50
51 classMediaTekCPU(CPU):52 defshow_cpu(self):53 print('联发科CPU')54
55 classAppleCPU(CPU):56 defshow_cpu(self):57 print('苹果CPU')58
59 classAndroid(OS):60 defshow_os(self):61 print('Android系统')62
63 classIOS(OS):64 defshow_os(self):65 print('iOS系统')66
67 #具体工厂
68 classMiFactory(PhoneFactory):69 defmake_cpu(self):70 returnSnapDragonCPU()71
72 defmake_os(self):73 returnAndroid()74
75 defmake_shell(self):76 returnBigShell()77
78
79 classHuaweiFactory(PhoneFactory):80 defmake_cpu(self):81 returnMediaTekCPU()82
83 defmake_os(self):84 returnAndroid()85
86 defmake_shell(self):87 returnSmallShell()88
89 classIPhoneFactory(PhoneFactory):90 defmake_cpu(self):91 returnAppleCPU()92
93 defmake_os(self):94 returnIOS()95
96 defmake_shell(self):97 returnAppleShell()98
99 #客户端
100 classPhone:101 def __init__(self,cpu,os,shell):102 self.cpu=cpu103 self.os=os104 self.shell=shell105
106 defshow_info(self):107 print('手机信息:')108 self.cpu.show_cpu()109 self.os.show_os()110 self.shell.show_shell()111
112 defmake_phone(factory):113 cpu=factory.make_cpu()114 os=factory.make_os()115 shell=factory.make_shell()116 returnPhone(cpu,os,shell)117
118 pl=make_phone(IPhoneFactory())119 pl.show_info()
建造者模式
内容:将一个复杂对象的构建与它表示分离,使得同样的构建过程可以创建不同的表示。
角色:抽象建造者(Builder),具体建造者(Concrete Builder),指挥者(Director),产品(Product)
建造者模式与抽象工厂模式相似,也用来创建复杂对象。主要区别是建造者模式着重一步步构造一个复杂对象,而抽象工厂模式着重于多个系列产品对象。
适用场景:当创建复杂对象的算法(Director)应该独立于该对象的组成部分时,当构造过程允许被构造的对象有不同的表示时(不同Builder)。
优点:隐藏了一个产品的内部结构和装配过程、将构造代码与表示代码分开、可以对构造过程进行更精细的控制
例子:
1 from abc importabstractmethod,ABCMeta2 classPlayer:3 def __init__(self,face=None,body=None,arm=None,leg=None):4 self.face=face5 self.body=body6 self.arm=arm7 self.leg=leg8
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 @abstractmethod15 defbuild_face(self):16 pass
17
18 @abstractmethod19 defbuild_arm(self):20 pass
21
22 @abstractmethod23 defbuild_leg(self):24 pass
25
26 @abstractmethod27 defbuild_body(self):28 pass
29
30 @abstractmethod31 defget_player(self):32 pass
33
34 classBeautifulWomanBuilder(PlayerBuilder):35 def __init__(self):36 self.player=Player()37
38 defbuild_face(self):39 self.player.face='漂亮脸蛋'
40
41 defbuild_arm(self):42 self.player.arm='细胳膊'
43
44 defbuild_leg(self):45 self.player.leg = '长腿'
46
47 defbuild_body(self):48 self.player.body = '细腰'
49
50 defget_player(self):51 returnself.player52
53
54 classPlayDirector:55 defbuild_player(self,builder):56 builder.build_body()57 builder.build_arm()58 builder.build_leg()59 builder.build_face()60 returnbuilder.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开始,并且当设计者发现需要更大的灵活性时,设计便会向其他创建模式演化。当你在设计标准之间进行权衡的时候,了解多个模式可以给你提供更多的选择余地。
依赖于继承的创建型模式:工厂方法模式
依赖于组合的创建型模式:抽象工厂模式、创建者模式