设计模式是解决问题的方案,学习现有的设计模式可以做到经验复用。使用设计模式可以在各种情况下解耦你的代码,让你的代码在运行时可以互相组合。 拥有设计模式词汇,在沟通时就能用更少的词汇来讨论,并且不需要了解底层细节。
参考链接
图说设计模式 CyC2018教程 (面试常考) Python系列干货之——Python与设计模式 python 23种常用模式设计总结 除了23种常见的模式以外,还有一些如MVC这样的模式 (面试常考)
创建型
创建型设计模式的意思是从实例对象生成的角度去解耦,根据实际需求,以更合理的创建对象。
单例模式 :创建一个同一时刻只能实例化一次的类,只要这个类的资源没有被释放,无法在被实例化。确保对象的唯一性。 工厂模式 :分简单工厂和抽象工厂,简单工厂是在创建一个对象时不向客户暴露内部细节,并提供一个 创建对象的通用接口。而抽象工厂则是提供一个接口,用于创建相关的对象家族。 建造者模式 :封装一个对象的构造过程,并允许按步骤构造。也可以理解为,将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。 原型模式 :使用原型实例指定要创建对象的类型,通过复制这个原型来创建新对象。
单例模式(Singleton)
Intent 涵义
确保一个类只有一个实例,并提供该实例的全局访问点。
Singleton.png
Example 举例
总线是计算机各种功能部件或者设备之间传送数据、控制信号等信息的公共通信解决方案之一。现假设有如下场景:某中央处理器(CPU)通过某种协议总线与一个信号灯相连,信号灯有64种颜色可以设置,中央处理器上运行着三个线程,都可以对这个信号灯进行控制,并且可以独立设置该信号灯的颜色。抽象掉协议细节(用打印表示),如何实现线程对信号等的控制逻辑。 加线程锁进行控制,无疑是最先想到的方法,但各个线程对锁的控制,无疑加大了模块之间的耦合。下面,我们就用设计模式中的单例模式,来解决这个问题。 具体到此例中,总线对象,就是一个单例,它仅有一个实例,各个线程对总线的访问只有一个全局访问点,即惟一的实例。
Code 代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 import timeimport threadingclass Singleton (object ): def __new__ (cls, *args, **kw ): if not hasattr (cls, '_instance' ): cls._instance = super (Singleton, cls).__new__(cls, *args, **kw) return cls._instanceclass Bus (Singleton ): lock = threading.RLock() def sendData (self, data ): self.lock.acquire() time.sleep(3 ) print("Sending Singal Data..." , data) self.lock.release() class VisitEntity (threading.Thread ): my_bus = "" name = "" def getName (self ): return self.name def setName (self, new_name ): self.name = new_name def run (self ): self.my_bus = Bus() self.my_bus.sendData(self.name) if __name__ == '__main__' : for i in range (3 ): print("Entity {index} begin to run..." .format (index=i)) my_entity = VisitEntity() my_entity.setName("Entity_{}" .format (str (i))) my_entity.start() Entity 0 begin to run... Entity 1 begin to run... Entity 2 begin to run... Sending Singal Data... Entity_0 Sending Singal Data... Entity_1 Sending Singal Data... Entity_2
Python中其他单例模式的实现方法(装饰器、共享属性等)
Python单例模式的4种实现方法
单例模式的优点和应用
单例模式的优点: 1、由于单例模式要求在全局内只有一个实例,因而可以节省比较多的内存空间 ; 2、全局只有一个接入点,可以更好地进行数据同步控制,避免多重占用 ; 3、单例可长驻内存,减少系统开销。
单例模式的应用举例: 1、生成全局惟一的序列号 ; 2、访问全局复用的惟一资源 ,如磁盘、总线等; 3、单个对象占用的资源过多,如数据库等; 4、系统全局统一管理 ,如Windows下的Task Manager; 5、网站计数器。
单例模式的缺点
1、单例模式的扩展是比较困难 的; 2、赋于了单例以太多的职责 ,某种程度上违反单一职责原则(六大原则后面会讲到); 3、单例模式是并发协作软件模块 中需要最先完成的,因而其不利于测试; 4、单例模式在某种情况下会导致“资源瓶颈 ”。
工厂模式(Factory)
Intent 涵义
抽象工厂:创建一系列相关或相互依赖抽象出来的的对象接口Interface,不需要具体指明实例化A类或B类 简单工厂:定义一个用于创建对象的接口函数Interface,让子类决定实例化哪一个类A或者B。 区别:简单工厂模式下一个工厂只负责生产一个类的实现。而抽象工厂则可以生成多种类的实现。
简单工厂(接口方法实现)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 class A : def __init__ (self ): self.word = "运行A" def run (self ): print(self.word)class B : def __init__ (self ): self.word = "运行B" def run (self ): print(self.word)def Interface (classname ): """ 工厂模式接口函数 :param classname: :return: """ run = dict (A=A, B=B) return run[classname]()if __name__ == '__main__' : test1 = Interface('A' ) test1.run() test2 = Interface('B' ) test2.run() 运行A 运行B
抽象工厂(接口方法实现)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 class A : def __init__ (self ): self.word = "运行A" def run (self ): print(self.word)class B : def __init__ (self ): self.word = "运行B" def run (self ): print(self.word)class Interface : """ 抽象工厂模式接口类 :param classname: :return: """ def __init__ (self, classname=None ): self.test = classname def run (self ): self.test().run()if __name__ == '__main__' : test1 = Interface() test1.test = A test1.run() test1.test = B test1.run() 运行A 运行B
继承方法实现抽象工厂模式,包含如下角色:
Product:抽象产品
ConcreteProduct:具体产品
Factory:抽象工厂
ConcreteFactory:具体工厂
最终,由具体工厂(继承自抽象工厂)生产具体产品(继承自抽象产品)。
factory.png
Example 举例
想必大家一定见过类似于麦当劳自助点餐台一类的点餐系统吧。在一个大的触摸显示屏上,有三类可以选择的上餐品:汉堡等主餐、小食、饮料。当我们选择好自己需要的食物,支付完成后,订单就生成了。下面,我们用今天的主角--工厂模式--来生成这些食物的逻辑主体。
Code 代码
这是一个抽象工厂的例子,实现方法是继承。首先,来看主餐的生成(仅以两种汉堡为例)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 class Burger (): name = "" price =0.0 def getPrice (self ): return self.price def setPrice (self,price ): self.price = price def getName (self ): return self.nameclass cheeseBurger (Burger ): def __init__ (self ): self.name = "cheese burger" self.price = 10.0 class spicyChickenBurger (Burger ): def __init__ (self ): self.name = "spicy chicken burger" self.price = 15.0
其次,是小食。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 class Snack (): name = "" price = 0.0 type = "SNACK" def getPrice (self ): return self.price def setPrice (self, price ): self.price = price def getName (self ): return self.nameclass chips (Snack ): def __init__ (self ): self.name = "chips" self.price = 6.0 class chickenWings (Snack ): def __init__ (self ): self.name = "chicken wings" self.price = 12.0
最后,是饮料。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 class Beverage (): name = "" price = 0.0 type = "BEVERAGE" def getPrice (self ): return self.price def setPrice (self, price ): self.price = price def getName (self ): return self.nameclass coke (Beverage ): def __init__ (self ): self.name = "coke" self.price = 4.0 class milk (Beverage ): def __init__ (self ): self.name = "milk" self.price = 5.0
以上的Burger,Snack,Beverage,都可以认为是该快餐店的产品,由于只提供了抽象方法,我们把它们叫抽象产品类,而cheese burger等6个由抽象产品类衍生出的子类,叫作具体产品类。 接下来,“工厂”就要出现了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 class foodFactory (): type = "" def createFood (self, foodClass ): print(self.type , "factory produce a instance." ) foodIns = foodClass() return foodInsclass burgerFactory (foodFactory ): def __init__ (self ): self.type = "BURGER" class snackFactory (foodFactory ): def __init__ (self ): self.type = "SNACK" class beverageFactory (foodFactory ): def __init__ (self ): self.type = "BEVERAGE"
同样,foodFactory为抽象的工厂类,而burgerFactory,snackFactory,beverageFactory为具体的工厂类。 在业务场景中,工厂模式是如何“生产”产品的呢?
if __name__=="__main__" : burger_factory = burgerFactory() snack_factorry = snackFactory() beverage_factory = beverageFactory() cheese_burger = burger_factory.createFood(cheeseBurger) print(cheese_burger.getName(),cheese_burger.getPrice()) chicken_wings = snack_factorry.createFood(chickenWings) print(chicken_wings.getName(),chicken_wings.getPrice()) coke_drink = beverage_factory.createFood(coke) print(coke_drink.getName(),coke_drink.getPrice())
输出
BURGER factory produce a instance.cheese burger 10 .0 SNACK factory produce a instance.chicken wings 12 .0 BEVERAGE factory produce a instance.coke 4 .0
可见,业务中先生成了工厂 ,然后用工厂中的 createFood
方法和对应的参数直接生成产品实例。
工厂模式的优点和应用
工厂模式、抽象工厂模式的优点: 1、工厂模式具有非常好的封装性,代码结构清晰 ;在抽象工厂模式中,其结构还可以随着需要进行更深或者更浅的抽象层级调整,非常灵活; 2、屏蔽产品类,使产品被使用业务场景和产品的功能细节分开,是比较典型的解耦框架。
工厂模式、抽象工厂模式的使用场景: 1、当系统实例要求比较灵活和可扩展时,可以考虑工厂模式或者抽象工厂模式实现。比如,在通信系统中,高层通信协议会很多样化,同时,上层协议依赖于下层协议,那么就可以对应建立对应层级的抽象工厂,根据不同的“产品需求”去生产定制的实例。
工厂类模式的不足
1、工厂模式相对于直接生成实例过程要复杂 一些,所以,在小项目中,可以不使用工厂模式; 2、抽象工厂模式中,产品类的扩展比较麻烦 。毕竟,每一个工厂对应每一类产品,产品扩展,就意味着相应的抽象工厂也要扩展。
建造者模式(Builder)
Intent 涵义
封装一个对象的构造过程,并允许按步骤构造。也可以理解为,将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
builder.png
Example 举例
还是上一次谈到的快餐点餐系统。只不过,今天我们从订单的角度来构造这个系统。
Code 代码
前面的部分一样,也是抽象产品和具体产品等类。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 class Burger (): name = "" price =0.0 def getPrice (self ): return self.price def setPrice (self,price ): self.price = price def getName (self ): return self.nameclass cheeseBurger (Burger ): def __init__ (self ): self.name = "cheese burger" self.price = 10.0 class spicyChickenBurger (Burger ): def __init__ (self ): self.name = "spicy chicken burger" self.price = 15.0 class Snack (): name = "" price = 0.0 type = "SNACK" def getPrice (self ): return self.price def setPrice (self, price ): self.price = price def getName (self ): return self.nameclass chips (Snack ): def __init__ (self ): self.name = "chips" self.price = 6.0 class chickenWings (Snack ): def __init__ (self ): self.name = "chicken wings" self.price = 12.0 class Beverage (): name = "" price = 0.0 type = "BEVERAGE" def getPrice (self ): return self.price def setPrice (self, price ): self.price = price def getName (self ): return self.nameclass coke (Beverage ): def __init__ (self ): self.name = "coke" self.price = 4.0 class milk (Beverage ): def __init__ (self ): self.name = "milk" self.price = 5.0
最终,我们是要建造一个订单,因而,需要一个订单类。假设,一个订单,包括一份主食,一份小食,一种饮料。(省去一些异常判断)
class order (): burger = "" snack = "" beverage = "" def __init__ (self, orderBuilder ): self.burger = orderBuilder.bBurger self.snack = orderBuilder.bSnack self.beverage = orderBuilder.bBeverage def show (self ): print("Burger: %s" %self.burger.getName()) print("Snack: %s" %self.snack.getName()) print("Beverage: %s" %self.beverage.getName())
代码中的 orderBuilder 是什么鬼?这个 orderBuilder 就是建造者模式中所谓的“建造者”了,先不要问为什么不在order类中把所有内容都填上,而非要用builder去创建。接着往下看。orderBuilder 的实现如下:
class orderBuilder (): bBurger = "" bSnack = "" bBeverage = "" def addBurger (self, xBurger ): self.bBurger = xBurger def addSnack (self, xSnack ): self.bSnack = xSnack def addBeverage (self, xBeverage ): self.bBeverage = xBeverage def build (self ): return order(self)
业务场景时,这么使用。
if __name__=="__main__" : order_builder = orderBuilder() order_builder.addBurger(spicyChickenBurger()) order_builder.addSnack(chips()) order_builder.addBeverage(milk()) order_1 = order_builder.build() order_1.show()
输出
Burger: spicy chicken burgerSnack: chipsBeverage: milk
建造者模式的作用,就是将“构建”和“表示”分离,以达到解耦的作用。 在上面订单的构建过程中,如果将order直接通过参数定义好(其构建与表示没有分离),同时在多处进行订单生成,此时需要修改订单内容,比如在之前的基础上加一个沙拉产品,则需要一处处去修改,业务风险也就提高了不少。使用了Builder之后,就只用修改orderBuilder类,新增一个 addSalad
的方法,在之后的调用过程中创建新订单时,增加一个 addSalad
方法的调用。
建造者模式的优点和使用场景
优点: 1、封装性好 ,用户可以不知道对象的内部构造和细节,就可以直接建造对象; 2、系统扩展容易 ; 3、建造者模式易于使用,非常灵活。在构造性的场景中很容易实现“流水线”; 4、便于控制细节 。
使用场景:
1、目标对象由组件构成的场景中,很适合建造者模式。 例如,在一款赛车游戏中,车辆生成时,需要根据级别、环境等,选择轮胎、悬挂、骨架等部件,构造一辆“赛车”; 2、在具体的场景中,对象内部接口需要根据不同的参数而调用顺序有所不同时,可以使用建造者模式。 例如:一个植物养殖器系统,对于某些不同的植物,浇水、施加肥料的顺序要求可能会不同,因而可以在Director中维护一个类似于队列的结构,在实例化时作为参数代入到具体建造者中。
建造者模式的缺点
1、“加工工艺”对用户不透明 。(封装的两面性)
原型模式(Prototype)
Intent 涵义
使用原型实例指定要创建对象的类型,通过复制这个原型来创建新对象。
Prototype.png
Example 举例
大家如果用过类似于Photoshop的平面设计软件,一定都知道图层的概念。图层概念的提出,使得设计、图形修改等操作更加便利。设计师既可以修改和绘制当前图像对象,又可以保留其它图像对象,逻辑清晰,且可以及时得到反馈。本节内容,将以图层为主角,介绍原型模式。
Code 代码
首先,设计一个图层对象。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 import copyclass simpleLayer : background = [0 ,0 ,0 ,0 ] content = "blank" def getContent (self ): return self.content def getBackgroud (self ): return self.background def paint (self,painting ): self.content = painting def setParent (self,p ): self.background[3 ] = p def fillBackground (self,back ): self.background = back def clone (self ): return copy.copy(self) def deep_clone (self ): return copy.deepcopy(self)
在实际的实现中,图层实现会很复杂,这里仅介绍相关的设计模式,做了比较大的抽象,用background表示背景的RGBA,简单用content表示内容,除了直接绘画,还可以设置透明度。新建图层,填充蓝底并画一只狗,可以简单表示如下:
if __name__ == "__main__" : dog_layer = simpleLayer() dog_layer.paint("Dog" ) dog_layer.fillBackground([0 ,0 ,255 ,0 ]) print("Background:" ,dog_layer.getBackgroud()) print("Painting:" ,dog_layer.getContent())
输出
Background: [0 , 0 , 255 , 0 ] Painting: Dog
接下来,如果需要再生成一个同样的图层,再填充同样的颜色,再画一只同样狗,该如何做呢?还是按照新建图层、填充背景、画的顺序么?或许你已经发现了,这里可以用复制的方法来实现,而复制(clone)这个动作,就是原型模式的精髓了。
if __name__ == "__main__" : dog_layer = simpleLayer() dog_layer.paint("Dog" ) dog_layer.fillBackground([0 ,0 ,255 ,0 ]) print("Background:" ,dog_layer.getBackgroud()) print("Painting:" ,dog_layer.getContent()) another_dog_layer = dog_layer.clone() print("Background:" , another_dog_layer.getBackgroud()) print("Painting:" , another_dog_layer.getContent())
输出
Background: [0 , 0 , 255 , 0 ] Painting: Dog Background: [0 , 0 , 255 , 0 ] Painting: Dog
原型模式的优点
1、性能极佳 ,直接拷贝比在内存里直接新建实例节省不少的资源; 2、简化对象创建 ,同时避免了构造函数的约束,不受构造函数的限制直接复制对象,是优点,也有隐患,这一点还是需要多留意一些。
使用场景:
1、对象在修改过后,需要复制多份的场景。 如本例和其它一些涉及到复制、粘贴的场景; 2、需要优化资源的情况。 如,需要在内存中创建非常多的实例,可以通过原型模式来减少资源消耗。此时,原型模式与工厂模式配合起来,不管在逻辑上还是结构上,都会达到不错的效果; 3、某些重复性的复杂工作不需要多次进行。 如对于一个设备的访问权限,多个对象不用各申请一遍权限,由一个设备申请后,通过原型模式将权限交给可信赖的对象,既可以提升效率,又可以节约资源。
原型模式的缺点
1、深拷贝和浅拷贝的使用需要事先考虑周到; 2、某些编程语言中,拷贝会影响到静态变量和静态函数的使用。
结构型
结构型的意思是处理类与类之间、系统与系统之间的逻辑结构,是协调类结构的重要模式设计思想。
适配器模式 :将其他类或系统中的方法封装一个统一接口来调用,从而达到适配各种系统方法的目的。 桥接模式 :处理抽象部分(类)与实体(实例化)之间的结构,可以使抽象部分和实例化部分单独变化不干扰。 组合模式 :用于设计一个有层次等级的系统,处理各层次之间的关系。 装饰模式 :用于扩展一个类或者系统的功能。 外观模式 :为子系统 中相似功能设计一组统一的调用界面。 享元模式 :让小粒度高频使用的类被共享 ,减少实例化过程,减少损耗。 代理模式 :用于控制一个对象的访问,让客户端通过代理访问,而不是直接访问。
适配器模式(Adapter)
Intent 涵义
把一个类接口转换成另一个用户需要的接口。
Adapter2.png
Adapter.png
Example 举例
以网络服务器为例
Code 代码
首先,构造一个网络服务器:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 info_struct = dict () info_struct["addr" ] = 10000 info_struct["content" ] = "" class Server : content="" def recv (self,info ): pass def send (self,info ): pass def show (self ): pass class infoServer (Server ): def recv (self,info ): self.content = info return ("recv OK!" ) def send (self,info ): pass def show (self ): print("SHOW:%s" %self.content)
infoServer
有接收和发送的功能,发送功能由于暂时用不到,保留。另外新加一个接口 show
,用来展示服务器接收的内容。接收的数据格式必须如 info_struct
所示,服务器仅接受 info_struct
的 content 字段。那么,如何给这个服务器设置一个白名单,使得只有白名单里的地址可以访问服务器呢? 修改Server结构是个方法,但这显然不符合软件设计原则中的单一职责原则 。在此基础之上,使用代理,是个不错的方法。代理配置如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 class serverProxy : pass class infoServerProxy (serverProxy ): server = "" def __init__ (self, server ): self.server=server def recv (self,info ): return self.server.recv(info) def show (self ): self.server.show()class whiteInfoServerProxy (infoServerProxy ): white_list=[] def recv (self,info ): try : assert type (info)==dict except : return "info structure is not correct" addr=info.get("addr" ,0 ) if not addr in self.white_list: return "Your address is not in the white list." else : content=info.get("content" ,"" ) return self.server.recv(content) def addWhite (self,addr ): self.white_list.append(addr) def rmvWhite (self,addr ): self.white_list.remove(addr) def clearWhite (self ): self.white_list=[]
代理中有一个 server
字段,控制代理的服务器对象,infoServerProxy
充当Server
的直接接口代理,而 whiteInfoServerProxy
直接继承了infoServerProxy
对象,在 whiteInfoServerProxy
中添加了 if not addr in self.white_list:
判断 ,同时加入了 white_list
和对白名单的操作。 这样,在场景中通过对白名单代理的访问,就可以实现服务器的白名单访问了。
if __name__=="__main__" : info_struct = dict () info_struct["addr" ] = 10010 info_struct["content" ] = "Hello World!" info_server = infoServer() info_server_proxy = whiteInfoServerProxy(info_server) print(info_server_proxy.recv(info_struct)) info_server_proxy.show() info_server_proxy.addWhite(10010 ) print(info_server_proxy.recv(info_struct)) info_server_proxy.show()
打印如下: Your address is not in the white list.SHOW: recv OK!SHOW: Hello World!
桥接模式(Bridge)
Intent 涵义
将抽象与实现分离开来,使它们可以独立变化。。它是一种对象结构型模式,又称为柄体(Handle and Body)模式或接口(Interface)模式。而Python程序设计中的桥接指的是抽象部分和实体部分的连接,简单来说是类和类实例化过称中的连接 。
Example 举例
设想如果要绘制矩形、圆形、椭圆、正方形,我们至少需要4个形状类,但是如果绘制的图形需要具有不同的颜色,如红色、绿色、蓝色等,此时至少有如下两种设计方案:
第一种设计方案是为每一种形状都提供一套各种颜色的版本。
第二种设计方案是根据实际需要对形状和颜色进行组合
对于有两个变化维度(即两个变化的原因)的系统,采用方案二来进行设计系统中类的个数更少,且系统扩展更为方便。设计方案二即是桥接模式的应用。桥接模式将继承关系转换为关联关系,从而降低了类与类之间的耦合,减少了代码编写量。
Code 代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 class A : def run (self, name ): print("my name is :{}" .format (name))class B : def run (self, name ): print("我的名字是:{}" .format (name))class Bridge : def __init__ (self, ager, classname ): self.ager = ager self.classname = classname def bridge_run (self ): self.classname.run(self.ager)if __name__ == '__main__' : test = Bridge('李华' , A()) test.bridge_run() test.ager = 'Tome' test.bridge_run() test.classname = B() test.bridge_run() test.ager = '李华' test.bridge_run()
上面这段示例代码的作用是李华和Tome分别用中英文介绍自己,演示抽象和实现之间的分离和桥接过称 。输出: my name is :李华my name is :Tome 我的名字是:Tome 我的名字是:李华
在提出桥梁模式的时候指出,桥梁模式的用意是"将抽象化(Abstraction)与实现化(Implementation)脱耦,使得二者可以独立地变化"。这句话有三个关键词,也就是抽象化、实现化和脱耦。 抽象化 存在于多个实体中的共同的概念性联系,就是抽象化。作为一个过程,抽象化就是忽略一些信息,从而把不同的实体当做同样的实体对待。 实现化 抽象化给出的具体实现,就是实现化。 脱耦 所谓耦合,就是两个实体的行为的某种强关联。而将它们的强关联去掉,就是耦合的解脱,或称脱耦。在这里,脱耦是指将抽象化和实现化之间的耦合解脱开,或者说是将它们之间的强关联改换成弱关联。
将两个角色之间的继承关系改为聚合关系,就是将它们之间的强关联改换成为弱关联。因此,桥梁模式中的所谓脱耦,就是指在一个软件系统的抽象化和实现化之间使用组合/聚合关系而不是继承关系,从而使两者可以相对独立地变化。
组合模式(Composite)
Intent 涵义
将对象组合成树形结构来表示“整体/部分”层次关系,允许用户以相同的方式处理单独对象和组合对象。
组件(Component)类是组合类(Composite)和叶子类(Leaf)的父类,可以把组合类看成是树的中间节点。 组合对象拥有一个或者多个组件对象,因此组合对 象的操作可以委托给组件对象去处理,而组件对象可以是另一个组合对象或者叶子对象。
Example 举例
如描述一家公司的层次结构,那么我们用办公室来表示节点,则总经理办公司是根节点,下面分别由人事办公室、业务办公室、生产办公室、财务办公室,每个办公室下面可以还有跟小的办公室,每个办公室都有职责、人员数、人员薪资等属性;
Code 代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 class ComponentBases : """部门抽象出来的基类""" def __init__ (self, name ): slef.name = name def add (self, obj ): pass def remove (self, obj ): pass def display (self, number ): pass class Node (ComponentBases ): def __init__ (self, name, duty ): self.name = name self.duty = duty self.children = [] def add (self, obj ): self.children.append(obj) def remove (self, obj ): self.children.remove(obj) def display (self, number=1 ): print("部门:{} 级别:{} 职责:{}" .format (self.name, number, self.duty)) n = number+1 for obj in self.children: obj.display(n)if __name__ == '__main__' : root = Node("总经理办公室" , "总负责人" ) node1 = Node("财务部门" , "公司财务管理" ) root.add(node1) node2 = Node("业务部门" , "销售产品" ) root.add(node2) node3 = Node("生产部门" , "生产产品" ) root.add(node3) node4 = Node("销售事业一部门" , "A产品销售" ) node2.add(node4) node5 = Node("销售事业二部门" , "B产品销售" ) node2.add(node5) root.display() ----------输出----------- 部门:总经理办公室 级别:1 职责:总负责人 部门:财务部门 级别:2 职责:公司财务管理 部门:业务部门 级别:2 职责:销售产品 部门:销售事业一部门 级别:3 职责:A产品销售 部门:销售事业二部门 级别:3 职责:B产品销售 部门:生产部门 级别:2 职责:生产产品
装饰模式(Decorator)
Intent 涵义
为对象动态添加功能,装饰者(Decorator)和具体组件(Concrete Component)都继承自组件(Component),具体组件的方法实现不需要依赖于其它对象,而装饰者组合了一个组件,这样它可以装饰其它装饰者或者具体组件。所谓装饰,就是把这个装饰者套在被装饰者之上,从而动态扩展被装饰者的功能。装饰者的方法有一部分是自己的,这属于它的功能,然后调用被装饰者的方法实现,从而也保留了被装饰者的功能。
Example 举例
一般有两种方式可以实现给一个类或对象增加行为:
继承机制,使用继承机制是给现有类添加功能的一种有效途径,通过继承一个现有类可以使得子类在拥有自身方法的同时还拥有父类的方法。但是这种方法是静态的,用户不能控制增加行为的方式和时机。
关联机制,即将一个类的对象嵌入另一个对象中,由另一个对象来决定是否调用嵌入对象的行为以便扩展自己的行为,我们称这个嵌入的对象为装饰器(Decorator)
装饰模式以对客户透明的方式动态地给一个对象附加上更多的责任,换言之,客户端并不会觉得对象在装饰前和装饰后有什么不同。装饰模式可以在不需要创造更多子类的情况下,将对象的功能加以扩展。这就是装饰模式的模式动机。
Code 代码
外观模式(Facade)
Intent 涵义
提供了一个统一的接口,用来访问子系统中的一群接口,从而让子系统更容易使用。
Example 举例
外部与一个子系统的通信必须通过一个统一的外观对象进行 ,为子系统中的一组接口提供一个一致的界面,外观模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。外观模式又称为门面模式,它是一种对象结构型模式。
外观模式(Facade),亦称“过程模式”, 为子系统中的一组接口提供一个一致的界面,Facade模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。
与接口相关的适配器模式,有所不同的是外观模式是为大系统下的小系统设计统一的接口,而适配器模式是针对不同系统各种接口调用而设计。
Code 代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 class API1 : def Save (self ): print('保存数据A' ) def Del (self ): print('删除数据A' )class API2 : def Save (self ): print('保存数据B' ) def Del (self ): print('删除数据B' )class Facade : def __init__ (self ): self._api1 = API1() self._api2 = API2() def SaveAll (self ): [obj.Save() for obj in [self._api1, self._api2]] def DelAll (self ): [obj.Save() for obj in [self._api1, self._api2]]if __name__ == '__main__' : test = Facade() test.SaveAll() test.DelAll() ---------------- 保存数据A 保存数据B 删除数据A 删除数据B
享元模式(Flyweight)
Intent 涵义
利用共享的方式来支持大量细粒度的对象,这些对象一部分内部状态是相同的。 享元模式下,有三种类: Flyweight:享元对象。 IntrinsicState:内部状态,享元对象共享内部状态。 ExtrinsicState:外部状态,每个享元对象的外部状态不同。
Example 举例
享元,可理解为python中的元类、最小粒度的类,系统中存在大量的相似对象时,可以选择享元模式提高资源利用率。
Code 代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 class FlyweightBase : def offer (self ): """享元基类""" pass class Flyweight (FlyweightBase ): """共享享元类""" def __init__ (self, name ): self.name = name def get_price (self, price ): print('产品类型:{} 详情:{}' .format (self.name, price))class FactoryFlyweight : """享元工厂类""" def __init__ (self ): self.product = {} def Getproduct (self, key ): if not self.product.get(key, None ): self.product[key] = Flyweight(key) return self.product[key]if __name__ == '__main__' : test = FactoryFlyweight() A = test.Getproduct("高端" ) A.get_price("香水:80" ) B = test.Getproduct("高端" ) B.get_price("面膜:800" ) 产品类型:高端 详情:香水:80 产品类型:高端 详情:面膜:800
在这个案例中共享了报价过程的类Flyweight,同一种产品类型的报价过程只会实例化一次 ,这就是享元模式最核心的要义:共享业务逻辑上的最小单元。
两个状态
内蕴状态 存储在享元内部,不会随环境的改变而有所不同,是可以共享的。 外蕴状态 是不可以共享的,它随环境的改变而改变的,因此外蕴状态是由客户端来保持(因为环境的变化是由客户端引起的)。
代理模式(Proxy)
Intent 涵义
控制对其它对象的访问,在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。
抽象角色 :通过接口或抽象类声明真实角色实现的业务方法。 代理角色 :实现抽象角色,是真实角色的代理,通过真实角色的业务逻辑方法来实现抽象方法,并可以附加自己的操作。 真实角色 :实现抽象角色,定义真实角色所要实现的业务逻辑,供代理角色调用。
Example 举例
远程(Remote)代理:为一个位于不同的地址空间的对象提供一个局域代表对象。这个不同的地址空间可以是在本机器中,也可是在另一台机器中。远程代理又叫做大使(Ambassador)。好处是系统可以将网络的细节隐藏起来,使得客户端不必考虑网络的存在。 虚拟(Virtual)代理(图片延迟加载的例子):根据需要创建一个资源消耗较大的对象,使得此对象只在需要时才会被真正创建。使用虚拟代理模式的好处就是代理对象可以在必要的时候才将被代理的对象加载;代理可以对加载的过程加以必要的优化。当一个模块的加载十分耗费资源的情况下,虚拟代理的好处就非常明显。 保护代理(Protection Proxy )控制对原始对象的访问。保护代理用于对象应该有不同 的访问权限的时候 智能引用(Smart Reference)代理:当一个对象被引用时,提供一些额外的操作,比如将对此对象调用的次数记录下来等。
Code 代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 class Jurisdiction : """权限类""" def level1 (self ): print('权限等级1' ) def level2 (self ): print('权限等级2' ) def level3 (self ): print('权限等级3' ) def level4 (self ): print('权限等级4' )class Proxy : def __init__ (self, name ): self.user = name self._jurisdiction = Jurisdiction() def leve (self ): if self.user == 'a' : return self._jurisdiction.level1() elif self.user == 'b' : return self._jurisdiction.level2() elif self.user == 'c' : return self._jurisdiction.level3() elif self.user == 'd' : return self._jurisdiction.level4() else : print('无此权限' )if __name__ == '__main__' : test = Proxy('a' ) test.leve() test.user = 'b' test.leve() test.user = 'c' test.leve() test.user = 'd' test.leve() test.user = 'e' test.leve() ----------------------- 权限等级1 权限等级2 权限等级3 权限等级4 无此权限
行为型
行为型设计模式是根据不同对象之间的关系进行代码设计。不仅仅是关于类和对象的,并是关于他们之间的相互作用。
责任链模式 :使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链发送该请求,直到有一个对象处理它为止。 观察者模式 :定义对象之间的一对多依赖,当一个对象状态改变时,它的所有依赖都会收到通知并且自动更新状态。主题(Subject)是被观察的对象,而其所有依赖者(Observer)称为观察者。
责任链模式
Intent 涵义
使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链发送该请求,直到有一个对象处理它为止。
Example 举例
Code 代码
命令模式
Intent 涵义
Example 举例
Code 代码
解释器模式
Intent 涵义
Example 举例
Code 代码
迭代器模式
Intent 涵义
Example 举例
Code 代码
中介器模式
Intent 涵义
Example 举例
Code 代码
备忘录模式
Intent 涵义
Example 举例
Code 代码
观察者模式
Intent 涵义
定义对象之间的一对多依赖,当一个对象状态改变时,它的所有依赖都会收到通知并且自动更新状态。主题(Subject)是被观察的对象,而其所有依赖者(Observer)称为观察者。
Example 举例
Code 代码
状态模式
Intent 涵义
Example 举例
Code 代码
策略模式
Intent 涵义
Example 举例
Code 代码
模板方法模式
Intent 涵义
Example 举例
Code 代码
访问者模式
Intent 涵义
Example 举例
Code 代码