此文章内容基本摘于 阿里达人 Tuso大神python
感谢大神知识分享,观摩其文章收益匪浅.web
连接地址:https://yq.aliyun.com/users/s2kca7gsykrca?spm=a2c4e.11153940.blogrightarea71197.1.1a9a6b10UZhTd6算法
在法理学中,法律规则与法律原则都是法律规范的重要构成。但两者也会有些不一样:法律规则是指采起必定的结构形式具体规定人们的法律权利、法律义务以及相应的法律后果的行为规范,内容比较明确,好比,交通法规中规定,禁止闯红灯;法律原则是指在必定法律体系中做为法律规则的指导思想,基本或本原的、综合的、稳定的原理和准则,内容上只包含“大方针”,而并未有具体规则,好比,若是车上有立刻临产的孕妇,闯红灯不会被处罚,这是符合重视生命的原则。设计模式与设计原则,基本符合规则与原则的关系,设计模式是一个个具体问题的解决方案,设计原则则反映了这些设计模式的指导思想;同时,设计原则可衍生出的设计模式也不只限于上述介绍到了23种设计模式,任何一种针对特定业务场景中的解决方法,虽然找不到对应的设计模式与之匹配,但若符合设计原则,也能够认为是一种全新的设计模式。从这个意义上来讲,设计模式是程序设计方法的形,而设计原则是程序设计方法的神。数据库
单一职责原则英文原名为Single Responsibility Principle,简称SRP原则。其含义为:应该有且仅有一个缘由引发类的变动。举个例子来讲明单一职责原则:一个视频播放系统,一个客户端类有两个功能接口,即视频播放接口和音频播放接口。虽然这样的设计很常见,但却不知足单一职责原则的。缘由是,若是对视频播放有变动需求或者对音频播放有修改需求,都会变动视频客户端的类结构。符合单一原则的设计是,将视频播放单元和音频播放单元各建一个类,播放客户端继承两个类,构成客户端。
单一职责原则的最大难点在于职责的划分,试想,以上划分是不是符合单一职责了?既是,也不是。试想,若是将视频传输和音频传输的协议信息和数据信息区分开,为符合这种粒度的单一职责原则就必需要有协议传输类和数据传输类的划分。若是接着细分,可能一个简单的小模块,都要设计很是多的类。所以,单一职责原则粒度的选择,应该根据业务流程和人员分工来进行考虑。一些基本的划分,彷佛已经成了行业规范性的内容,好比,业务逻辑与用户信息管理的划分等。编程
里氏替换原则英文原名为Liskov Substitution Principle,简称LSP原则。它是面向对象设计的最为基本原则之一。 里氏替换原则的含义为:任何基类能够出现的地方,子类必定能够出现。 LSP是继承复用的基石,只有当子类能够替换掉基类,软件单位的功能不受到影响时,基类才能真正被复用,子类也可以在基类的基础上增长新的行为。举例说明:对于一个鸟类,能够衍生出麻雀、喜鹊、布谷等子类,这些子类均可继承鸟类的鸣叫、飞行、吃食等接口。而对于一个鸡类,虽然它在生物学上属于鸟类,但它不会飞,那么符合LSP设计原则的状况下,鸡就不该该是鸟的一个子类:在鸟类调用飞行接口的地方,鸡类并不能出现。若是鸡类要使用鸟类的接口,应该使用关联关系,而不是继承关系。设计模式
依赖倒置原则英文原名为Dependence Inversion Principle,简称DIP原则。它的含义为:高层模块不该该依赖于低层模块,二者都应该依赖其抽象。抽象不该该依赖于细节,细节应该依赖于抽象。咱们将每一个不可细分的逻辑叫做原子逻辑,原子逻辑组装,造成低层模块,低层模块组装造成高层模块。依赖倒置原则的含义为,高层模块和低层模块都应该由各自的抽象模块派生而来,同时接口设计应该依赖于抽象,而非具体模块。举个例子:司机与汽车是依赖的关系,司机能够有实习司机类、老司机类等派生;汽车能够有轿车、SUV、卡车等派生类。若是司机中设计一个接口drive,汽车是其参数,符合DIP设计原则的参数,应该是在基类司机类中,将基类汽车类做为参数,而司机的派生类中,drive的参数一样应该为基类汽车类,而不该该是汽车类的任一个派生类。若是规定实习司机只能开轿车等业务逻辑,应该在其接口中进行判断,而不该该将参数替换成子类轿车。安全
接口隔离原则英文原名为Interface Segregation Principle,简称ISP原则。其含义为:类间的依赖关系不该该创建一个大的接口,而应该创建其最小的接口,即客户端不该该依赖那些它不须要的接口。这里的接口的概念是很是重要的。从逻辑上来说,这里的接口能够指一些属性和方法的集合;从业务上来说,接口就能够指特定业务下的接口(如函数,URL调用等)。接口应该尽可能小,同时仅留给客户端必要的接口,弃用没有必要的接口。举例说明:若是要根据具体的数据,生成饼图、直方图、表格,这个类该如何设计?若是将生成饼图、直方图、表格等“接口”(这里的接口就是“操做”的集合的概念),写在一个类中,是不符合接口隔离原则的。符合ISP原则的设计应该是设计三个类,每一个类分别实现饼图、直方图、表格的绘制。
接口隔离原则和单一职责原则同样,涉及到粒度的问题,解决粒度大小,一样依赖于具体的业务场景,须要读者根据实践去权衡。服务器
迪米特法则(Law of Demeter)也叫最少知识原则,英文Least Knowledge Principle,简称LKP原则。其含义为:一个对象应该对其它对象有最少的了解。举例说明:一个公司有多个部门,每一个部门有多个员工,若是公司CEO要下发通知给每一个员工,是调用接口直接通知全部员工么?其实否则,CEO只需和它的“朋友”类部门Leader交流就好,部门Leader再下发通知信息便可。而CEO类不须要与员工进行“交流”。
迪米特法则要求对象应该仅对本身的朋友类交流,而不该该对非朋友类交流。那什么才是朋友类呢?通常来讲,朋友类具备如下特征:
1)当前对象自己(self);
2)以参量形式传入到当前对象方法中的对象;
3)当前对象的实例变量直接引用的对象;
4)当前对象的实例变量若是是一个汇集,那么汇集中的元素也都是朋友;
5)当前对象所建立的对象。网络
开闭原则英文原名为Open Closed Principle,简称OCP原则。其含义为:一个软件实体,如类、模块、函数等,应该对扩展开放,对修改关闭。开闭原则是很是基础的一个原则,也有人把开闭原则称为“原则的原则”。前面讲到过,模块分原子模块,低层模块,高层模块,业务层能够认为是最高层次的模块。对扩展开放,意味着模块的行为是能够扩展的,当高层模块需求改变时,咱们能够对低层模块进行扩展,使其具备知足高层模块的新功能;对修改关闭,即对低层模块行为进行扩展时,没必要改动模块的源代码。最理想的状况是,业务变更时,仅修改业务代码,不修改依赖的模块(类、函数等)代码,经过扩展依赖的模块单元来实现业务变化。举例说明:假设一个原始基类水果类,苹果类是它的派生类,苹果中包含水果的各类属性,如形状、颜色等;另有两个类,农民类和花园类,最高层次(业务层次)为农民在花园种苹果。若是此时,农民决定不种苹果了,改种梨,符合OCP原则的设计应该为基于水果类构建一个新的类,即梨类(对扩展开放),而并不该该去修改苹果类,使它成为一个梨类(对修改关闭)。修改应仅在最高层,即业务层中进行。数据结构
因为设计原则是设计模式的提炼,于是设计原则的好处与设计模式是一致的,即:代码易于理解;更适于团体合做;适应需求变化等。
工厂模式:工厂方法模式是一种解耦结构,工厂类只须要知道抽象产品类,符合最少知识原则(迪米特法则);同时符合依赖倒置原则和里氏替换原则;
抽象工厂模式:抽象工厂模式具备工厂模式的优势,但同时,若是产品族要扩展,工厂类也要修改,违反了开闭原则;
模板模式:优秀的扩展能力符合开闭原则。
代理模式:代理模式在业务逻辑中将对主体对象的操做进行封装,合适的应用会符合开闭原则和单一职责原则;事实上,几乎带有解耦做用的结构类设计模式都多少符合些开闭原则;
门面模式:门面模式不符合开闭原则,有时不符合单一职责原则,如若不注意,也会触碰接口隔离原则;
组合模式:符合开闭原则,但因为通常在拼接树时使用实现类,故不符合依赖倒置原则;
桥梁模式:桥梁模式堪称依赖倒置原则的典范,同时也符合开闭原则。
策略模式:符合开闭原则,但高层模块调用时,不符合迪米特法则。行为类设计模式多少会符合些单一职责原则,典型的如观察者模式、中介者模式、访问者模式等;
责任链模式:符合单一职责原则和迪米特法则;
命令模式:符合开闭原则。
在不一样的业务逻辑中,不一样的设计模式也会显示出不一样的设计原则特色,从这个意义上来讲,设计模式是设计原则的体现,但体现不是固定的,是根据业务而有所不一样的。
设计模式基本上本着“高内聚、低耦合”的原则
1.建立类设计模式
2.结构类设计模式
3.行为类设计模式
单例模式
工厂模式
抽象工厂模式
原型模式
建造者模式
代理模式
装饰器模式
适配器模式
门面模式
组合模式
享元模式
桥梁模式
策略模式
责任链模式
命令模式
中介者模式
模板模式
迭代器模式
访问者模式
观察者模式
解释器模式
备忘录模式
状态模式
单例模式是指:保证一个类仅有一个实例,并提供一个访问它的全局访问点。
具体到此例中,总线对象,就是一个单例,它仅有一个实例,各个线程对总线的访问只有一个全局访问点,即唯一的实例。
单例模式的优势:
一、因为单例模式要求在全局内只有一个实例,于是能够节省比较多的内存空间;
二、全局只有一个接入点,能够更好地进行数据同步控制,避免多重占用;
三、单例可长驻内存,减小系统开销。
一、生成全局唯一的序列号;
二、访问全局复用的唯一资源,如磁盘、总线等;
三、单个对象占用的资源过多,如数据库等;
四、系统全局统一管理,如Windows下的Task Manager;
五、网站计数器。
一、单例模式的扩展是比较困难的;
二、赋于了单例以太多的职责,某种程度上违反单一职责原则(六大原则后面会讲到);
三、单例模式是并发协做软件模块中须要最早完成的,于是其不利于测试;
四、单例模式在某种状况下会致使“资源瓶颈”。
#encoding=utf8 import threading import time #这里使用方法__new__来实现单例模式 class Singleton(object):#抽象单例 def __new__(cls, *args, **kw): if not hasattr(cls, '_instance'): orig = super(Singleton, cls) cls._instance = orig.__new__(cls,*args,**kw) return cls._instance #总线 class Bus(Singleton): lock = threading.RLock() def sendData(self,data): self.lock.acquire() time.sleep(3) print ("Sending Signal Data...",data) self.lock.release() #线程对象,为更加说明单例的含义,这里将Bus对象实例化写在了run里 class VisitEntity(threading.Thread): my_bus="" name="" def getName(self): return self.name def setName(self, name): self.name=name def run(self): self.my_bus=Bus() self.my_bus.sendData(self.name) if __name__=="__main__": for i in range(20): print("Entity %d begin to run..."%i) my_entity=VisitEntity() my_entity.setName("Entity_"+str(i)) my_entity.start()
定义一个用于建立对象的接口,让子类决定实例化哪一个类。
工厂方法使一个类的实例化延迟到其子类。
其产品类定义产品的公共属性和接口,工厂类定义产品实例化的“方式”。
工厂模式、抽象工厂模式的优势:
一、工厂模式巨有很是好的封装性,代码结构清晰;在抽象工厂模式中,其结构还能够随着须要进行更深或者更浅的抽象层级调整,很是灵活;
二、屏蔽产品类,使产品的被使用业务场景和产品的功能细节能够分而开发进行,是比较典型的解耦框架。
工厂模式、抽象工厂模式的使用场景:
一、当系统实例要求比较灵活和可扩展时,能够考虑工厂模式或者抽象工厂模式实现。好比,
在通讯系统中,高层通讯协议会不少样化,同时,上层协议依赖于下层协议,那么就能够对应创建对应层级的抽象工厂,根据不一样的“产品需求”去生产定制的实例。
一、工厂模式相对于直接生成实例过程要复杂一些,因此,在小项目中,能够不使用工厂模式;
二、抽象工厂模式中,产品类的扩展比较麻烦。毕竟,每个工厂对应每一类产品,产品扩展,就意味着相应的抽象工厂也要扩展。
''' 快餐点餐系统 想必你们必定见过相似于麦当劳自助点餐台一类的点餐系统吧。 在一个大的触摸显示屏上,有三类能够选择的上餐品:汉堡等主餐、小食、饮料。 当咱们选择好本身须要的食物,支付完成后,订单就生成了。 下面,咱们用今天的主角--工厂模式--来生成这些食物的逻辑主体。 ''' # ------------------------商品(汉堡) class Burger(): name="" price=0.0 def getPrice(self): return self.price def setPrice(self,price): self.price=price def getName(self): return self.name class 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.name class 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.name class 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 foodFactory(): type = "" def createFood(self,foodClass): print (self.type," factory produce a instance.") foodIns=foodClass() return foodIns class 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" # 简单工厂模式(省去实例化工厂类的过程,直接经过简单工厂实例化商品) class simpleFoodFactory(): @classmethod def createFood(cls,foodClass): print ("Simple factory produce a instance.") foodIns = foodClass() return foodIns 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()) # 简单工厂模式(省去了实例化工厂类的过程) spicy_chicken_burger = simpleFoodFactory.createFood(spicyChickenBurger) print (spicy_chicken_burger.getName(),spicy_chicken_burger.getPrice()) ''' 仍是在上述例子中,createFood方法中必须传入foodClass才能够指定生成的food实例种类, 若是,将每个细致的产品都创建对应的工厂(如cheeseBurger创建对应一个cheeseBurgerFactory), 这样,生成食物时,foodClass也没必要指定。事实上,此时,burgerFactory就是具体食物工厂的一层抽象。 这种模式,就是抽象工厂模式。 '''
一、封装性好,用户能够不知道对象的内部构造和细节,就能够直接建造对象;
二、系统扩展容易;
三、建造者模式易于使用,很是灵活。在构造性的场景中很容易实现“流水线”;
四、便于控制细节。
使用场景:
一、目标对象由组件构成的场景中,很适合建造者模式。例如,在一款赛车游戏中,车辆生成时,须要根据级别、环境等,选择轮胎、悬挂、骨架等部件,构造一辆“赛车”;
二、在具体的场景中,对象内部接口须要根据不一样的参数而调用顺序有所不一样时,可使用建造者模式。例如:一个植物养殖器系统,对于某些不一样的植物,浇水、施加肥料的顺序要求可能会不一样,于是能够在Director中维护一个相似于队列的结构,在实例化时做为参数代入到具体建造者中。
一、“加工工艺”对用户不透明。(封装的两面性)
# ------------------------商品(汉堡) class Burger(): name="" price=0.0 def getPrice(self): return self.price def setPrice(self,price): self.price=price def getName(self): return self.name class 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.name class 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.name class 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()) 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) class orderDirector(): order_builder="" def __init__(self,order_builder): self.order_builder=order_builder def createOrder(self,burger,snack,beverage): self.order_builder.addBurger(burger) self.order_builder.addSnack(snack) self.order_builder.addBeverage(beverage) return self.order_builder.build() 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() # 统一调度 orderDirector = orderDirector(orderBuilder()) display_show = orderDirector.createOrder(spicyChickenBurger(),chips(),milk()) display_show.show()
优势:
一、性能极佳,直接拷贝比在内存里直接新建实例节省很多的资源;
二、简化对象建立,同时避免了构造函数的约束,不受构造函数的限制直接复制对象,是优势,也有隐患,这一点仍是须要多留意一些。
使用场景:
一、对象在修改事后,须要复制多份的场景。如本例和其它一些涉及到复制、粘贴的场景;
二、须要优化资源的状况。如,须要在内存中建立很是多的实例,能够经过原型模式来减小资源消耗。此时,原型模式与工厂模式配合起来,无论在逻辑上仍是结构上,都会达到不错的效果;
三、某些重复性的复杂工做不须要屡次进行。如对于一个设备的访问权限,多个对象不用各申请一遍权限,由一个设备申请后,经过原型模式将权限交给可信赖的对象,既能够提高效率,又能够节约资源。
一、深拷贝和浅拷贝的使用须要事先考虑周到;
二、某些编程语言中,拷贝会影响到静态变量和静态函数的使用。
''' 你们若是用过相似于Photoshop的平面设计软件,必定都知道图层的概念。 图层概念的提出,使得设计、图形修改等操做更加便利。 设计师既能够修改和绘制当前图像对象,又能够保留其它图像对象,逻辑清晰,且能够及时获得反馈。 本节内容,将以图层为主角,介绍原型模式。 ''' from copy import copy, deepcopy class 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(self) def deep_clone(self): return deepcopy(self) if __name__=="__main__": dog_layer=simpleLayer() dog_layer.paint("Dog") dog_layer.fillBackground([0,0,255,0]) print ("Original Background:",dog_layer.getBackgroud()) print ("Original Painting:",dog_layer.getContent()) # 浅复制 / 深复制 another_dog_layer=dog_layer.clone() # another_dog_layer = dog_layer.deep_clone() another_dog_layer.setParent(128) another_dog_layer.paint("Puppy") print ("Original Background:", dog_layer.getBackgroud()) print ("Original Painting:", dog_layer.getContent()) print ("Copy Background:", another_dog_layer.getBackgroud()) print ("Copy Painting:", another_dog_layer.getContent())
代理模式是一种使用频率很是高的模式,在多个著名的开源软件和当前多个著名的互联网产品后台程序中都有所应用。
下面咱们用一个抽象化的简单例子,来讲明代理模式。
为某对象提供一个代理,以控制对此对象的访问和控制。代理模式在使用过程当中,应尽可能对抽象主题类进行代理,而尽可能不要对加过修饰和方法的子类代理。
如上例中,若是有一个xServer继承了Server,并新加了方法xMethod,xServer的代理应以Server为主题进行设计,而尽可能不要以xServer为主题,以xServer为 主题的代理能够从ServerProxy继承并添加对应的方法。在JAVA中,讲到代理模式,不得不会提到动态代理。动态代理是实现AOP(面向切面编程)的重要实现手段。而在Python中,不多会提到动态代理,而AOP则会以另外一种模式实现:装饰模式。有关AOP的相关内容,咱们会在装饰模式这一节中进行说明。
优势:
一、职责清晰:很是符合单一职责原则,主题对象实现真实业务逻辑,而非本职责的事务,交由代理完成;
二、扩展性强:面对主题对象可能会有的改变,代理模式在不改变对外接口的状况下,能够实现最大程度的扩展;
三、保证主题对象的处理逻辑:代理能够经过检查参数的方式,保证主题对象的处理逻辑输入在理想范围内。
应用场景:
一、针对某特定对象进行功能和加强性扩展。如IP防火墙、远程访问代理等技术的应用;
二、对主题对象进行保护。如大流量代理,安全代理等;
三、减轻主题对象负载。如权限代理等。
可能会下降总体业务的处理效率和速度。
#该服务器接受以下格式数据,addr表明地址,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) 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=[] 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() print("----------------") # 加入白名单,接受数据 info_server_proxy.addWhite(10010) print (info_server_proxy.recv(info_struct)) info_server_proxy.show()
优势:
一、装饰器模式是继承方式的一个替代方案,能够轻量级的扩展被装饰对象的功能;
二、Python的装饰器模式是实现AOP的一种方式,便于相同操做位于不一样调用位置的统一管理。
应用场景:
一、须要扩展、加强或者减弱一个类的功能,如本例。
多层装饰器的调试和维护有比较大的困难。
''' 快餐店卖可乐时,能够选择加冰,若是加冰的话,要在原价上加0.3元; 卖牛奶时,能够选择加糖,若是加糖的话,要原价上加0.5元。怎么解决这样的问题? ''' 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.name class 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 drinkDecorator(): def getName(self): pass def getPrice(self): pass class iceDecorator(drinkDecorator): def __init__(self, beverage): self.beverage = beverage def getName(self): return self.beverage.getName() + " +ice" def getPrice(self): return self.beverage.getPrice() + 0.3 class sugarDecorator(drinkDecorator): def __init__(self, beverage): self.beverage = beverage def getName(self): return self.beverage.getName() + " +sugar" def getPrice(self): return self.beverage.getPrice() + 0.5 if __name__=="__main__": coke_cola=coke() print ("Name:%s"%coke_cola.getName()) print ("Price:%s"%coke_cola.getPrice()) ice_coke=iceDecorator(coke_cola) print ("Name:%s" % ice_coke.getName()) print ("Price:%s" % ice_coke.getPrice())
将一个类的接口变换成客户端期待的另外一种接口,从而使本来因接口不匹配而没法在一块儿工做的两个类可以在一块儿工做。适配器模式和装饰模式有必定的类似性,都起包装的做用,但两者本质上又是不一样的,装饰模式的结果,是给一个对象增长了一些额外的职责,而适配器模式,则是将另外一个对象进行了“假装”。适配器能够认为是对如今业务的补偿式应用,因此,尽可能不要在设计阶段使用适配器模式,在两个系统须要兼容时能够考虑使用适配器模式。
优势:
一、适配器模式可让两个接口不一样,甚相当系不大的两个类一块儿运行;
二、提升了类的复用度,通过“假装”的类,能够充当新的角色;
三、适配器能够灵活“拆卸”。
应用场景:
一、不修改现有接口,同时也要使该接口适用或兼容新场景业务中,适合使用适配器模式。
例如,在一个嵌入式系统中,本来要将数据从Flash读入,如今须要将数据从磁盘读入,
这种状况可使用适配器模式,将从磁盘读入数据的接口进行“假装”,以从Flash中读数据的接口形式,从磁盘读入数据。
适配器模式与原配接口相比,毕竟增长了一层调用关系,因此,在设计系统时,不要使用适配器模式。
''' 假设某公司A与某公司B须要合做,公司A须要访问公司B的人员信息,但公司A与公司B协议接口不一样,该如何处理? 先将公司A和公司B针对各自的人员信息访问系统封装了对象接口。 ''' class ACpnStaff: name="" id="" phone="" def __init__(self,id): self.id=id def getName(self): print ("A protocol getName method...id:%s"%self.id) return self.name def setName(self,name): print ("A protocol setName method...id:%s"%self.id) self.name=name def getPhone(self): print ("A protocol getPhone method...id:%s"%self.id) return self.phone def setPhone(self,phone): print ("A protocol setPhone method...id:%s"%self.id) self.phone=phone class BCpnStaff: name="" id="" telephone="" def __init__(self,id): self.id=id def get_name(self): print ("B protocol get_name method...id:%s"%self.id) return self.name def set_name(self,name): print ("B protocol set_name method...id:%s"%self.id) self.name=name def get_telephone(self): print ("B protocol get_telephone method...id:%s"%self.id) return self.telephone def set_telephone(self,telephone): print ("B protocol get_name method...id:%s"%self.id) self.telephone=telephone class CpnStaffAdapter: b_cpn="" def __init__(self,id): self.b_cpn=BCpnStaff(id) def getName(self): return self.b_cpn.get_name() def getPhone(self): return self.b_cpn.get_telephone() def setName(self,name): self.b_cpn.set_name(name) def setPhone(self,phone): self.b_cpn.set_telephone(phone) if __name__=="__main__": acpn_staff=ACpnStaff("123") acpn_staff.setName("X-A") acpn_staff.setPhone("10012345678") print ("A Staff Name:%s"%acpn_staff.getName()) print ("A Staff Phone:%s"%acpn_staff.getPhone()) bcpn_staff=CpnStaffAdapter("456") bcpn_staff.setName("Y-B") bcpn_staff.setPhone("99987654321") print ("B Staff Name:%s"%bcpn_staff.getName()) print ("B Staff Phone:%s"%bcpn_staff.getPhone())
要求一个子系统的外部与其内部的通讯必须经过一个统一的对象进行。门面模式提供一个高层次的接口,使得子系统更易于使用。门面模式注重“统一的对象”,也就是提供一个访问子系统的接口。门面模式与以前说过的模板模式有相似的地方,都是对一些须要重复方法的封装。但从本质上来讲,是不一样的。模板模式是对类自己的方法的封装,其被封装的方法也能够单独使用;而门面模式,是对子系统的封装,其被封装的接口理论上是不会被单独提出来用的。
优势:
一、减小了系统之间的相互依赖,提升了系统的灵活;
二、提升了总体系统的安全性:封装起的系统对外的接口才能够用,隐藏了不少内部接口细节,若方法不容许使用,则在门面中能够进行灵活控制。
使用场景:
一、为一个复杂的子系统提供一个外界访问的接口。这类例子是生活仍是蛮常见的,例如电视遥控器的抽象模型,电信运营商的用户交互设备等;
二、须要简化操做界面时。例如常见的扁平化系统操做界面等,在生活中和工业中都很常见。
门面模式的缺点在于,不符合开闭原则,一旦系统成形后须要修改,几乎只能重写门面代码,这比继承或者覆写等方式,或者其它一些符合开闭原则的模式风险都会大一些。
''' 假设有一组火警报警系统,由三个子元件构成:一个警报器,一个喷水器,一个自动拨打电话的装置。其抽象以下: 在业务中若是须要将三个部件启动,例如,若是有一个烟雾传感器,检测到了烟雾。在业务环境中须要作以下操做: ''' class AlarmSensor: def run(self): print ("Alarm Ring...") class WaterSprinker: def run(self): print ("Spray Water...") class EmergencyDialer: def run(self): print ("Dial 119...") # if __name__=="__main__": # alarm_sensor=AlarmSensor() # water_sprinker=WaterSprinker() # emergency_dialer=EmergencyDialer() # alarm_sensor.run() # water_sprinker.run() # emergency_dialer.run() ''' 若是在多个业务场景中须要启动三个部件,怎么办?Ctrl+C加上Ctrl+V么? 固然能够这样,但做为码农的基本修养之一,减小重复代码是应该会被很轻易想到的方法。 这样,须要将其进行封装,在设计模式中,被封装成的新对象,叫作门面。门面构建以下: ''' class EmergencyFacade: def __init__(self): self.alarm_sensor=AlarmSensor() self.water_sprinker=WaterSprinker() self.emergency_dialer=EmergencyDialer() def runAll(self): self.alarm_sensor.run() self.water_sprinker.run() self.emergency_dialer.run() if __name__=="__main__": emergency_facade=EmergencyFacade() emergency_facade.runAll()
将对象组合成树形结构以表示“部分”和“总体”的层次结构,使得用户对单个对象和组合对象的使用具备一致性。
优势:
一、节点增长和减小是很是自由和方便的,这也是树形结构的一大特色;
二、全部节点,无论是分支节点仍是叶子结点,无论是调用一个结点,仍是调用一个结点群,都是很是方便的。
使用场景:
一、维护部分与总体的逻辑关系,或者动态调用总体或部分的功能接口,能够考虑使用组合模式。
例如,很是多的操做系统(如Linux)都把文件系统设计成树形结构,
再好比说分布式应用中借助Zookeeper,也能够组织和调用分布式集群中的结点功能。
因为叶子结点和分支结点直接使用了实现类,而不方便使用抽象类,这大大限制了接口的影响范围;
若结点接口发生变动,对系统形成的风险会比较大。
''' 每个公司都有本身的组织结构,越是大型的企业,其组织结构就会越复杂。 大多数状况下,公司喜欢用“树形”结构来组织复杂的公司人事关系和公司间的结构关系。 通常状况下,根结点表明公司的最高行政权利单位,分支节点表示一个个部门,而叶子结点则会用来表明每个员工。 每个结点的子树,表示该结点表明的部门所管理的单位。 假设一个具备HR部门,财务部门和研发部门,同时在全国有分支公司的总公司,其公司结构, 能够表示成以下逻辑: ''' class Company: name = '' def __init__(self, name): self.name = name def add(self, company): pass def remove(self, company): pass def display(self, depth): pass def listDuty(self): pass class ConcreteCompany(Company): childrenCompany = None def __init__(self, name): Company.__init__(self,name) self.childrenCompany = [] def add(self, company): self.childrenCompany.append(company) def remove(self, company): self.childrenCompany.remove(company) def display(self, depth): print('-'*depth + self.name) for component in self.childrenCompany: component.display(depth+1) def listDuty(self): for component in self.childrenCompany: component.listDuty() class HRDepartment(Company): def __init__(self, name): Company.__init__(self,name) def display(self, depth): print ('-'*depth + self.name) def listDuty(self): #履行职责 print ('%s\t Enrolling & Transfering management.' % self.name) class FinanceDepartment(Company): def __init__(self, name): Company.__init__(self,name) def display(self, depth): print ("-" * depth + self.name) def listDuty(self): #履行职责 print ('%s\tFinance Management.'%self.name) class RdDepartment(Company): def __init__(self,name): Company.__init__(self,name) def display(self, depth): print ("-"*depth+self.name) def listDuty(self): print ("%s\tResearch & Development."% self.name) if __name__=="__main__": root = ConcreteCompany('HeadQuarter') root.add(HRDepartment('HQ HR')) root.add(FinanceDepartment('HQ Finance')) root.add(RdDepartment("HQ R&D")) comp = ConcreteCompany('East Branch') comp.add(HRDepartment('East.Br HR')) comp.add(FinanceDepartment('East.Br Finance')) comp.add(RdDepartment("East.Br R&D")) root.add(comp) comp1 = ConcreteCompany('Northast Branch') comp1.add(HRDepartment('Northeast.Br HR')) comp1.add(FinanceDepartment('Northeast.Br Finance')) comp1.add(RdDepartment("Northeast.Br R&D")) comp.add(comp1) comp2 = ConcreteCompany('Southeast Branch') comp2.add(HRDepartment('Southeast.Br HR')) comp2.add(FinanceDepartment('Southeast.Br Finance')) comp2.add(RdDepartment("Southeast.Br R&D")) comp.add(comp2) root.display(1) root.listDuty()
使用共享对象支持大量细粒度对象。大量细粒度的对象的支持共享,可能会涉及这些对象的两类信息:内部状态信息和外部状态信息。内部状态信息就是可共享出来的信息,它们存储在享元对象内部,不会随着特定环境的改变而改变;外部状态信息就不可共享的信息了。享元模式中只包含内部状态信息,而不该该包含外部状态信息。这点在设计业务架构时,应该有所考虑。
优势:
一、减小重复对象,大大节约了系统资源。
使用场景:
一、系统中存在大量的类似对象时,能够选择享元模式提升资源利用率。咖啡订购平台比较小,
若假设一个电商平台,每一个买家和卖家创建起买卖关系后,买家对象和卖家对象都是占用资源的。
若是一个卖家同时与多个买家创建起买卖关系呢?此时享元模式的优点就体现出来了;
二、须要缓冲池的场景中,可使用享元模式。如进程池,线程池等技术,就可使用享元模式(事实上,不少的池技术中已经使得了享元模式)。
一、享元模式虽然节约了系统资源,但同时也提升了系统的复杂性,尤为当遇到外部状态和内部状态混在一块儿时,须要先将其进行分离,才可使用享元模式。不然,会引发逻辑混乱或业务风险;
二、享元模式中须要额外注意线程安全问题。
class Customer: coffee_factory="" name="" def __init__(self,name,coffee_factory): self.name=name self.coffee_factory=coffee_factory def order(self,coffee_name): print ("%s ordered a cup of coffee:%s"%(self.name,coffee_name)) return self.coffee_factory.getCoffee(coffee_name) ''' 按照通常的处理流程,用户在网上预订咖啡,其表明用户的Customer类中生成一个Coffee类,直到交易流程结束。 整个流程是没有问题的。若是,随着网站用户愈来愈多,单位时间内购买咖啡的用户也愈来愈多,并发量愈来愈大, 对系统资源的消耗也会愈来愈大,极端状况下,会形成宕机等严重后果。此时,高效利用资源,就显得很是重要了。 简单分析下业务流程,高并发下用户数量增长,而该模型下,每一个用户点一杯咖啡,就会产生一个咖啡实例, 若是一种咖啡在该时间内被不少用户点过,那么就会产生不少一样咖啡的实例。 避免重复实例的出现,是节约系统资源的一个突破口。 相似于单例模式,咱们这里在咖啡实例化前,增长一个控制实例化的类:咖啡工厂。 ''' class CoffeeFactory(): coffee_dict = {} def getCoffee(self, name): if self.coffee_dict.__contains__(name) == False: self.coffee_dict[name] = Coffee(name) return self.coffee_dict[name] def getCoffeeCount(self): return len(self.coffee_dict) if __name__=="__main__": coffee_factory=CoffeeFactory() customer_1=Customer("A Client",coffee_factory) customer_2=Customer("B Client",coffee_factory) customer_3=Customer("C Client",coffee_factory) c1_capp=customer_1.order("cappuccino") c1_capp.show() c2_mocha=customer_2.order("mocha") c2_mocha.show() c3_capp=customer_3.order("cappuccino") c3_capp.show() print ("Num of Coffee Instance:%s"%coffee_factory.getCoffeeCount())
将抽象与实现解耦(注意此处的抽象和实现,并不是抽象类和实现类的那种关系,而是一种角色的关系,这里须要好好区分一下),可使其独立变化。在形如上例中,Pen只负责画,但没有形状,它终究是不知道要画什么的,因此咱们把它叫作抽象化角色;而Shape是具体的形状,咱们把它叫作实现化角色。抽象化角色和实现化角色是解耦的,这也就意味着,所谓的桥,就是抽象化角色的抽象类和实现化角色的抽象类之间的引用关系。
优势:
一、抽象角色与实现角色相分离,两者能够独立设计,不受约束;
二、扩展性强:抽象角色和实现角色能够很是灵活地扩展。
应用场景:
一、不适用继承或者原继承关系中抽象类可能频繁变更的状况,能够将原类进行拆分,拆成实现化角色和抽象化角色。例如本例中,若将形状、粗细、绘画样式等属于聚集在一个类中,一旦抽象类中有所变更,将形成巨大的风险;
二、重用性比较大的场景。好比开关控制逻辑的程序,开关就是抽象化角色,开关的形式有不少种,操做的实现化角色也有不少种,采用桥梁模式,(如当前例子)开关便可进行复用,总体会将设计的粒度减少。
一、增长对系统理解的难度。
''' 在介绍原型模式的一节中,咱们举了个图层的例子,这一小节内容,咱们一样以相似画图的例子,说明一种结构类设计模式:桥梁模式。 在一个画图程序中,常会见到这样的状况:有一些预设的图形,如矩形、圆形等,还有一个对象-画笔,调节画笔的类型(如画笔仍是画刷, 仍是毛笔效果等)并设定参数(如颜色、线宽等),选定图形,就能够在画布上画出想要的图形了。要实现以上需求,先从最抽象的元素开始设计, 即形状和画笔(暂时忽略画布,同时忽略画笔参数,只考虑画笔类型)。 ''' class Shape(): name="" param="" def __init__(self,*param): pass def getName(self): return self.name def getParam(self): return self.name,self.param class Rectangle(Shape): def __init__(self,long,width): super().__init__() self.name="Rectangle" self.param="Long:%s Width:%s"%(long,width) print ("Create a rectangle:%s"%self.param) class Circle(Shape): def __init__(self,radius): super().__init__() self.name="Circle" self.param="Radius:%s"%radius print ("Create a circle:%s"%self.param) class Pen(): shape="" type="" def __init__(self,shape): self.shape=shape def draw(self): pass class NormalPen(Pen): def __init__(self,shape): super().__init__(shape) self.type="Normal Line" def draw(self): print ("DRAWING %s:%s----PARAMS:%s"%(self.type,self.shape.getName(),self.shape.getParam())) class BrushPen(Pen): def __init__(self,shape): super().__init__(shape) self.type="Brush Line" def draw(self): print ("DRAWING %s:%s----PARAMS:%s" % (self.type,self.shape.getName(), self.shape.getParam())) if __name__=="__main__": normal_pen=NormalPen(Rectangle("20cm","10cm")) brush_pen=BrushPen(Circle("15cm")) normal_pen.draw() brush_pen.draw()
定义一组算法,将每一个算法都封装起来,并使他们之间可互换。以上述例子为例,customer类扮演的角色(Context)直接依赖抽象策略的接口,在具体策略实现类中便可定义个性化的策略方式,且能够方便替换。仔细比较一下桥接模式和策略模式,若是把策略模式的Context设计成抽象类和实现类的方式,那么策略模式和桥接模式就能够划等号了。从类图看上去,桥接模式比策略模式多了对一种角色(抽象角色)的抽象。两者结构的高度同构,也只能让咱们从使用意图上去区分两种模式:桥接模式解决抽象角色和实现角色均可以扩展的问题;而策略模式解决算法切换和扩展的问题。
优势:
一、各个策略能够自由切换:这也是依赖抽象类设计接口的好处之一;
二、减小代码冗余;
三、扩展性优秀,移植方便,使用灵活。
应用场景:
一、算法策略比较常常地须要被替换时,可使用策略模式。如如今超市前台,会常遇到刷卡、某宝支付、某信支付等方式,就能够参考策略模式。
一、项目比较庞大时,策略可能比较多,不便于维护;
二、策略的使用方必须知道有哪些策略,才能决定使用哪个策略,这与迪米特法则是相违背的。
''' 假设某司维护着一些客户资料,须要在该司有新产品上市或者举行新活动时通知客户。现通知客户的方式有两种: 短信通知、邮件通知。应如何设计该系统的客户通知部分? 为解决该问题,咱们先构造客户类,包括客户经常使用的联系方式和基本信息,同时也包括要发送的内容。 ''' class customer: customer_name="" snd_way="" info="" phone="" email="" def setPhone(self,phone): self.phone=phone def setEmail(self,mail): self.email=mail def getPhone(self): return self.phone def getEmail(self): return self.email def setInfo(self,info): self.info=info def setName(self,name): self.customer_name=name def setBrdWay(self,snd_way): self.snd_way=snd_way def sndMsg(self): self.snd_way.send(self.info) class msgSender: dst_code="" def setCode(self,code): self.dst_code=code def send(self,info): pass class emailSender(msgSender): def send(self,info): print ("EMAIL_ADDRESS:%s EMAIL:%s"%(self.dst_code,info)) class textSender(msgSender): def send(self,info): print ("TEXT_CODE:%s EMAIL:%s"%(self.dst_code,info)) if __name__=="__main__": customer_x=customer() customer_x.setName("CUSTOMER_X") customer_x.setPhone("10023456789") customer_x.setEmail("customer_x@xmail.com") customer_x.setInfo("Welcome to our new party!") text_sender=textSender() text_sender.setCode(customer_x.getPhone()) customer_x.setBrdWay(text_sender) customer_x.sndMsg() mail_sender=emailSender() mail_sender.setCode(customer_x.getEmail()) customer_x.setBrdWay(mail_sender) customer_x.sndMsg()
使多个对象都有机会处理请求,从而避免了请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有对象处理它为止。
优势:
一、将请求者与处理者分离,请求者并不知道请求是被哪一个处理者所处理,易于扩展。
应用场景:
一、若一个请求可能由一个对请求有链式优先级的处理群所处理时,能够考虑责任链模式。除本例外,银行的客户请求处理系统也能够用责任链模式实现(VIP客户和普通用户处理方式固然会有不一样)。
一、若是责任链比较长,会有比较大的性能问题;
二、若是责任链比较长,若业务出现问题,比较难定位是哪一个处理者的问题。
''' 假设有这么一个请假系统: 员工若想要请3天之内(包括3天的假),只须要直属经理批准就能够了; 若是想请3-7天,不只须要直属经理批准,部门经理须要最终批准; 若是请假大于7天,不光要前两个经理批准,也须要总经理最终批准。 相似的系统相信你们都遇到过,那么该如何实现呢?首先想到的固然是if…else…, 但一旦遇到需求变更,其臃肿的代码和复杂的耦合缺点都显现出来。 简单分析下需求,“假条”在三个经理间是单向传递关系,像一条链条同样, 于是,咱们能够用一条“链”把他们进行有序链接。 ''' class manager(): successor = None name = '' def __init__(self, name): self.name = name def setSuccessor(self, successor): self.successor = successor def handleRequest(self, request): pass class lineManager(manager): def handleRequest(self, request): if request.requestType == 'DaysOff' and request.number <= 3: print ('%s:%s Num:%d Accepted OVER' % (self.name, request.requestContent, request.number)) else: print('%s:%s Num:%d Accepted CONTINUE' % (self.name, request.requestContent, request.number)) if self.successor != None: self.successor.handleRequest(request) class departmentManager(manager): def handleRequest(self, request): if request.requestType == 'DaysOff' and request.number <= 7: print ('%s:%s Num:%d Accepted OVER' % (self.name, request.requestContent, request.number)) else: print ('%s:%s Num:%d Accepted CONTINUE' % (self.name, request.requestContent, request.number)) if self.successor != None: self.successor.handleRequest(request) class generalManager(manager): def handleRequest(self, request): if request.requestType == 'DaysOff': print ('%s:%s Num:%d Accepted OVER' % (self.name, request.requestContent, request.number)) class request(): requestType = '' requestContent = '' number = 0 if __name__=="__main__": # 实例化 给个层级部门 line_manager = lineManager('LINE MANAGER') department_manager = departmentManager('DEPARTMENT MANAGER') general_manager = generalManager('GENERAL MANAGER') # 将各个层级相互嵌套 1 > 2 > 3 line_manager.setSuccessor(department_manager) department_manager.setSuccessor(general_manager) # 模拟请求(1天假) req = request() req.requestType = 'DaysOff' req.requestContent = 'Ask 1 day off' req.number = 1 line_manager.handleRequest(req) print("------------------------------------") # 模拟请求(5天假) req.requestType = 'DaysOff' req.requestContent = 'Ask 5 days off' req.number = 5 line_manager.handleRequest(req) print("------------------------------------") # 模拟请求(10天假) req.requestType = 'DaysOff' req.requestContent = 'Ask 10 days off' req.number = 10 line_manager.handleRequest(req)
将一个请求封装成一个对象,从而可使用不一样的请求将客户端参数化,对请求排队或者记录请求日志,能够提供命令的撤销和恢复功能。命令模式中一般涉及三类对象的抽象:Receiver,Command,Invoker(本例中的waiterSys)只有一个Invoker的命令模式也能够抽象成一个相似的“星形网络”,但与以前介绍的中介者模式不一样,单纯的命令模式更像是一个辐射状的结构,由Invoker直接对Receiver传递命令,而通常不反向传递,中介者模式“星形网络”的中心,是个协调者,抽象结节间的信息流所有或者部分是双向的。另外,命令模式的定义中提到了“撤销和恢复功能”,也给了各位开发人员一个命令模式使用过程当中的建议:
各个Receiver中能够设计一个回滚接口,支持命令的“撤销”。
优势:
一、低耦合:调用者和接收者之间没有什么直接关系,两者经过命令中的execute接口联系;
二、扩展性好:新命令很容易加入,也很容易拼出“组合命令”。
应用场景:
一、触发-反馈机制的系统,均可以使用命令模式思想。如基于管道结构的命令系统(如SHELL),能够直接套用命令模式;此外,GUI系统中的操做反馈(如点击、键入等),也可使用命令模式思想。
一、若是业务场景中命令比较多,那么对应命令类和命令对象的数量也会增长,这样系统会膨胀得很大。
''' 饭店的点餐系统有什么不一样嘛? 大伙想一想看,在大多数饭店中,当服务员已经接到顾客的点单,录入到系统中后,根据不一样的菜品,会有不一样的后台反应。 好比,饭店有凉菜间、热菜间、主食间,那当服务员将菜品录入到系统中后,凉菜间会打印出顾客所点的凉菜条目, 热菜间会打印出顾客所点的热菜条目,主食间会打印出主食条目。那这个系统的后台模式该如何设计? 固然,直接在场景代码中加if…else…语句判断是个方法,可这样作又一次加剧了系统耦合, 违反了单一职责原则,遇到系统需求变更时,又会轻易违反开闭原则。因此,咱们须要从新组织一下结构。 能够将该系统设计成前台服务员系统和后台系统,后台系统进一步细分红主食子系统,凉菜子系统,热菜子系统。后台三个子系统设计以下: ''' class backSys(): def cook(self,dish): pass class mainFoodSys(backSys): def cook(self,dish): print ("MAINFOOD:Cook %s"%dish) class coolDishSys(backSys): def cook(self,dish): print ("COOLDISH:Cook %s"%dish) class hotDishSys(backSys): def cook(self,dish): print ("HOTDISH:Cook %s"%dish) class waiterSys(): menu_map=dict() commandList=[] def setOrder(self,command): print ("WAITER:Add dish") self.commandList.append(command) def cancelOrder(self,command): print ("WAITER:Cancel order...") self.commandList.remove(command) def notify(self): print ("WAITER:Nofify...") for command in self.commandList: command.execute() class Command(): receiver = None def __init__(self, receiver): self.receiver = receiver def execute(self): pass class foodCommand(Command): dish="" def __init__(self,receiver,dish): super().__init__(receiver) self.receiver=receiver self.dish=dish def execute(self): self.receiver.cook(self.dish) class mainFoodCommand(foodCommand): pass class coolDishCommand(foodCommand): pass class hotDishCommand(foodCommand): pass class menuAll: menu_map=dict() def loadMenu(self):#加载菜单,这里直接写死 self.menu_map["hot"] = ["Yu-Shiang Shredded Pork", "Sauteed Tofu, Home Style", "Sauteed Snow Peas"] self.menu_map["cool"] = ["Cucumber", "Preserved egg"] self.menu_map["main"] = ["Rice", "Pie"] def isHot(self,dish): if dish in self.menu_map["hot"]: return True return False def isCool(self,dish): if dish in self.menu_map["cool"]: return True return False def isMain(self,dish): if dish in self.menu_map["main"]: return True return False if __name__=="__main__": dish_list=["Yu-Shiang Shredded Pork","Sauteed Tofu, Home Style","Cucumber","Rice"]#顾客点的菜 waiter_sys=waiterSys() main_food_sys=mainFoodSys() cool_dish_sys=coolDishSys() hot_dish_sys=hotDishSys() menu=menuAll() # 加载菜单 menu.loadMenu() # 点菜单分拣所点的菜分属哪一个档口 for dish in dish_list: if menu.isCool(dish): cmd=coolDishCommand(cool_dish_sys,dish) elif menu.isHot(dish): cmd=hotDishCommand(hot_dish_sys,dish) elif menu.isMain(dish): cmd=mainFoodCommand(main_food_sys,dish) else: continue waiter_sys.setOrder(cmd) waiter_sys.notify()
用一个中介对象封装一系列的对象交互。中介者使各对象不须要显式地互相做用,从而使其耦合松散,并能够独立地改变它们之间的交互。
优势:
一、减小类与类的依赖,下降了类和类之间的耦合;
二、容易扩展规模。
应用场景:
一、设计类图时,出现了网状结构时,能够考虑将类图设计成星型结构,这样就可使用中介者模式了。
如机场调度系统(多个跑道、飞机、指挥塔之间的调度)、路由系统;
著名的MVC框架中,其中的C(Controller)就是M(Model)和V(View)的中介者。
一、中介者自己的复杂性可能会很大,例如,同事类的方法若是不少的话,本例中的execute逻辑会很复杂。
''' 有一个手机仓储管理系统,使用者有三方: 销售、仓库管理员、采购。需求是:销售一旦达成订单,销售人员会经过系统的销售子系统部分通知仓储子系统, 仓储子系统会将可出仓手机数量减小,同时通知采购管理子系统当前销售订单;仓储子系统的库存到达阈值如下, 会通知销售子系统和采购子系统,并督促采购子系统采购;采购完成后,采购人员会把采购信息填入采购子系统, 采购子系统会通知销售子系统采购完成,并通知仓库子系统增长库存。 从需求描述来看,每一个子系统都和其它子系统有所交流,在设计系统时, 若是直接在一个子系统中集成对另两个子系统的操做,一是耦合太大,二是不易扩展。 为解决这类问题,咱们须要引入一个新的角色-中介者-来将“网状结构”精简为“星形结构”。 (为充分说明设计模式,某些系统细节暂时不考虑,例如:仓库满了怎么办该怎么设计。相似业务性的内容暂时不考虑) ''' class colleague(): mediator = None def __init__(self,mediator): self.mediator = mediator class purchaseColleague(colleague): def buyStuff(self,num): print ("PURCHASE:Bought %s"%num) self.mediator.execute("buy",num) def getNotice(self,content): print ("PURCHASE:Get Notice--%s"%content) class warehouseColleague(colleague): total=0 threshold=100 def setThreshold(self,threshold): self.threshold=threshold def isEnough(self): if self.total<self.threshold: print ("WAREHOUSE:Warning...Stock is low... ") self.mediator.execute("warning",self.total) return False else: return True def inc(self,num): self.total+=num print ("WAREHOUSE:Increase %s"%num) self.mediator.execute("increase",num) self.isEnough() def dec(self,num): if num>self.total: print ("WAREHOUSE:Error...Stock is not enough") else: self.total-=num print ("WAREHOUSE:Decrease %s"%num) self.mediator.execute("decrease",num) self.isEnough() class salesColleague(colleague): def sellStuff(self,num): print ("SALES:Sell %s"%num) self.mediator.execute("sell",num) def getNotice(self, content): print ("SALES:Get Notice--%s" % content) class abstractMediator(): purchase="" sales="" warehouse="" def setPurchase(self,purchase): self.purchase=purchase def setWarehouse(self,warehouse): self.warehouse=warehouse def setSales(self,sales): self.sales=sales def execute(self,content,num): pass class stockMediator(abstractMediator): def execute(self,content,num): print ("MEDIATOR:Get Info--%s"%content) if content=="buy": self.warehouse.inc(num) self.sales.getNotice("Bought %s"%num) elif content=="increase": self.sales.getNotice("Inc %s"%num) self.purchase.getNotice("Inc %s"%num) elif content=="decrease": self.sales.getNotice("Dec %s"%num) self.purchase.getNotice("Dec %s"%num) elif content=="warning": self.sales.getNotice("Stock is low.%s Left."%num) self.purchase.getNotice("Stock is low. Please Buy More!!! %s Left"%num) elif content=="sell": self.warehouse.dec(num) self.purchase.getNotice("Sold %s"%num) else: pass if __name__=="__main__": mobile_mediator=stockMediator()#先配置 mobile_purchase=purchaseColleague(mobile_mediator) mobile_warehouse=warehouseColleague(mobile_mediator) mobile_sales=salesColleague(mobile_mediator) mobile_mediator.setPurchase(mobile_purchase) mobile_mediator.setWarehouse(mobile_warehouse) mobile_mediator.setSales(mobile_sales) mobile_warehouse.setThreshold(2000) mobile_purchase.buyStuff(3000) mobile_sales.sellStuff(120)
定义一个操做中的算法的框架,而将一些步骤延迟到子类中,使得子类能够不改变一个算法的结构便可从新定义该算法的某些特定的步骤。子类实现的具体方法叫做基本方法,实现对基本方法高度的框架方法,叫做模板方法。模板模式的优势和应用
一、可变的部分能够充分扩展,不变的步骤能够充分封装;
二、提取公共代码,减小冗余代码,便于维护;
三、具体过程能够定制,整体流程方便掌控。
使用场景:
一、某超类的子类中有公有的方法,而且逻辑基本相同,可使用模板模式。必要时可使用钩子方法约束其行为。具体如本节例子;
二、比较复杂的算法,能够把核心算法提取出来,周边功能在子类中实现。例如,机器学习中的监督学习算法有不少,如决策树、KNN、SVM等,但机器学习的流程大体相同,都包含输入样本、拟合(fit)、预测等过程,这样就能够把这些过程提取出来,构造模板方法,并经过钩子方法控制流程。
一、模板模式在抽象类中定义了子类的方法,即子类对父类产生了影响,部分影响了代码的可读性。
''' 投资股票是种常见的理财方式,我国股民愈来愈多,实时查询股票的需求也愈来愈大。今天,咱们经过一个简单的股票查询客户端来认识一种简单的设计模式:模板模式。 根据股票代码来查询股价分为以下几个步骤:登陆、设置股票代码、查询、展现。构造以下的虚拟股票查询器: ''' class StockQueryDevice(): stock_code="0" stock_price=0.0 def login(self,usr,pwd): pass def setCode(self,code): self.stock_code=code def queryPrice(self): pass def showPrice(self): pass def operateQuery(self,usr,pwd,code): self.login(usr,pwd) self.setCode(code) self.queryPrice() self.showPrice() return True class WebAStockQueryDevice(StockQueryDevice): def login(self,usr,pwd): if usr=="myStockA" and pwd=="myPwdA": print ("Web A:Login OK... user:%s pwd:%s"%(usr,pwd)) return True else: print ("Web A:Login ERROR... user:%s pwd:%s"%(usr,pwd)) return False def queryPrice(self): print ("Web A Querying...code:%s "%self.stock_code) self.stock_price=20.00 def showPrice(self): print ("Web A Stock Price...code:%s price:%s"%(self.stock_code,self.stock_price)) class WebBStockQueryDevice(StockQueryDevice): def login(self,usr,pwd): if usr=="myStockB" and pwd=="myPwdB": print ("Web B:Login OK... user:%s pwd:%s"%(usr,pwd)) return True else: print ("Web B:Login ERROR... user:%s pwd:%s"%(usr,pwd)) return False def queryPrice(self): print ("Web B Querying...code:%s "%self.stock_code) self.stock_price=30.00 def showPrice(self): print ("Web B Stock Price...code:%s price:%s"%(self.stock_code,self.stock_price)) def operateQuery(self,usr,pwd,code): if not self.login(usr,pwd): return False self.setCode(code) self.queryPrice() self.showPrice() return True if __name__=="__main__": web_a_query_dev=WebAStockQueryDevice() web_a_query_dev.operateQuery("myStockA","myPwdA","12345")
它提供一种方法,访问一个容器对象中各个元素,而又不须要暴露对象的内部细节。
class MyIter(object): def __init__(self, n): self.index = 0 self.n = n def __iter__(self): # 只能打印一遍平方值。解决办法是,在__iter__中不返回实例,而再返回一个对象,写成: # return self return MyIter(self.n) def __next__(self): if self.index < self.n: value = self.index**2 self.index += 1 return value else: raise StopIteration() if __name__=="__main__": x_square=MyIter(10) for x in x_square: print (x) for x in x_square: print (x) ''' 这样,在每次迭代时均可以将迭代器“初始化”,就能够屡次迭代了。 另外,在python中,使用生成器能够很方便的支持迭代器协议。 生成器经过生成器函数产生,生成器函数能够经过常规的def语句来定义, 可是不用return返回,而是用yield一次返回一个结果,在每一个结果之间挂起和继续它们的状态,来自动实现迭代协议。 '''
封装一些做用于某种数据结构中的各元素的操做,它能够在不改变数据结构的前提下定义于做用于这些元素的新操做。提到访问者模式,就不得不提一下双分派。分派分为静态分派和动态分派。首先解释下静态分派,静态分派即根据请求者的名称和接收到的参数,决定多态时处理的操做。好比在Java或者C++中,定义名称相同但参数不一样的函数时,会根据最终输入的参数来决定调用哪一个函数。双分派顾名思义,即最终的操做决定于两个接收者的类型,在本例中,药品和工做人员互相调用了对方(药品的accept和工做人员的visit中,对方都是参数),就是双分派的一种应用。Python原生是不支持静态分派的,于是也不直接支持更高层次的分派。访问者模式实现的分派,是一种动态双分派。但这并不妨碍Python经过访问者模式实现一种基于类的“双分派效果”。Python多分派能够参考David Mertz 博士的一篇文章:可爱的Python:多分派—用多元法泛化多样性。
优势:
一、将不一样的职责很是明确地分离开来,符合单一职责原则;
二、职责的分开也直接致使扩展很是优良,灵活性很是高,加减元素和访问者都很是容易。
应用场景:
一、要遍历不一样的对象,根据对象进行不一样的操做的场景;或者一个对象被多个不一样对象顺次处理的状况,能够考虑使用访问者模式。除本例外,报表生成器也可使用访问者模式实现,报表的数据源由多个不一样的对象提供,每一个对象都是Visitor,报表这个Element顺次Accept各访问者完善并生成对象。
一、访问者得知了元素细节,与最小隔离原则相悖;
二、元素变动依旧可能引发Visitor的修改。
''' 假设一个药房,有一些大夫,一个药品划价员和一个药房管理员,它们经过一个药房管理系统组织工做流程。 大夫开出药方后,药品划价员肯定药品是否正常,价格是否正确;经过后药房管理员进行开药处理。该系统能够如何实现? 最简单的想法,是分别用一个一个if…else…把划价员处理流程和药房管理流程实现,这样作的问题在于, 扩展性不强,并且单一性不强,一旦有新药的加入或者划价流程、开药流程有些变更,会牵扯比较多的改动。 今天介绍一种解决这类问题的模式:访问者模式。 ''' # 构造药品类和工做人员类: class Medicine: name="" price=0.0 def __init__(self,name,price): self.name=name self.price=price def getName(self): return self.name def setName(self,name): self.name=name def getPrice(self): return self.price def setPrice(self,price): self.price=price def accept(self,visitor): pass class Antibiotic(Medicine): def accept(self,visitor): visitor.visit(self) class Coldrex(Medicine): def accept(self,visitor): visitor.visit(self) # 药品类中有两个子类,抗生素和感冒药; class Visitor: name="" def setName(self,name): self.name=name def visit(self,medicine): pass class Charger(Visitor): def visit(self,medicine): print("CHARGE: %s lists the Medicine %s. Price:%s " % (self.name,medicine.getName(),medicine.getPrice())) class Pharmacy(Visitor): def visit(self,medicine): print("PHARMACY:%s offers the Medicine %s. Price:%s" % (self.name,medicine.getName(),medicine.getPrice())) ''' 做人员分为划价员和药房管理员。 在药品类中,有一个accept方法,其参数是个visitor;而工做人员就是从Visitor类中继承而来的,也就是说, 他们就是Visitor,都包含一个visit方法,其参数又恰是medicine。药品做为处理元素, 依次容许(Accept)Visitor对其进行操做,这就比如是一条流水线上的一个个工人,对产品进行一次次的加工。 整个业务流程还差一步,即药方类的构建(流水线大机器)。 ''' class ObjectStructure: pass class Prescription(ObjectStructure): medicines=[] def addMedicine(self,medicine): self.medicines.append(medicine) def rmvMedicine(self,medicine): self.medicines.append(medicine) def visit(self,visitor): for medc in self.medicines: medc.accept(visitor) # 药方类将待处理药品进行整理,并组织Visitor依次处理。 if __name__=="__main__": yinqiao_pill=Coldrex("Yinqiao Pill",2.0) penicillin=Antibiotic("Penicillin",3.0) doctor_prsrp=Prescription() doctor_prsrp.addMedicine(yinqiao_pill) doctor_prsrp.addMedicine(penicillin) charger=Charger() charger.setName("Doctor Strange") pharmacy=Pharmacy() pharmacy.setName("Doctor Wei") doctor_prsrp.visit(charger) doctor_prsrp.visit(pharmacy)
定义对象间一种一对多的依赖关系,使得当该对象状态改变时,全部依赖于它的对象都会获得通知,并被自动更新。观察者模式的通知方式能够经过直接调用等同步方式实现(如函数调用,HTTP接口调用等),也能够经过消息队列异步调用(同步调用指被观察者发布消息后,必须等全部观察者响应结束后才能够进行接下来的操做;异步调用指被观察者发布消息后,便可进行接下来的操做。)。事实上,许多开源的消息队列就直接支持发布-订阅模式,如Zero MQ等。
优势:
一、观察者与被观察者之间是抽象耦合的;
二、能够将许多符合单一职责原则的模块进行触发,也能够很方便地实现广播。
应用场景:
一、消息交换场景。如上述说到的消息队列等;
二、多级触发场景。好比支持中断模式的场景中,一个中断即会引起一连串反应,就可使用观察者模式。
一、观察者模式可能会带来总体系统效率的浪费;
二、若是被观察者之间有依赖关系,其逻辑关系的梳理须要费些心思。
''' 在门面模式中,咱们提到过火警报警器。 在当时,咱们关注的是经过封装减小代码重复。而今天,咱们将从业务流程的实现角度,来再次实现该火警报警器。 ''' class AlarmSensor: def run(self): print ("Alarm Ring...") class WaterSprinker: def run(self): print ("Spray Water...") class EmergencyDialer: def run(self): print ("Dial 119...") class Observer: def update(self): pass class AlarmSensor(Observer): def update(self,action): print ("Alarm Got: %s" % action) self.runAlarm() def runAlarm(self): print ("Alarm Ring...") class WaterSprinker(Observer): def update(self,action): print ("Sprinker Got: %s" % action) self.runSprinker() def runSprinker(self): print ("Spray Water...") class EmergencyDialer(Observer): def update(self,action): print ("Dialer Got: %s"%action) self.runDialer() def runDialer(self): print ("Dial 119...") class Observed: observers=[] action="" def addObserver(self,observer): self.observers.append(observer) def notifyAll(self): for obs in self.observers: obs.update(self.action) class smokeSensor(Observed): def setAction(self,action): self.action=action def isFire(self): return True if __name__=="__main__": alarm=AlarmSensor() sprinker=WaterSprinker() dialer=EmergencyDialer() smoke_sensor=smokeSensor() smoke_sensor.addObserver(alarm) smoke_sensor.addObserver(sprinker) smoke_sensor.addObserver(dialer) if smoke_sensor.isFire(): smoke_sensor.setAction("On Fire!") smoke_sensor.notifyAll()
给定一种语言,定义它的文法表示,并定义一个解释器,该解释器使用该表示来解释语言中的句子。典型的解释器模式中会有终结符和非终结符之说,语法也根据两种终结符,决定语句最终含义。上例中,非终结符就是空格,终结符就是整个句尾。
优势:
一、在语法分析的场景中,具备比较好的扩展性。规则修改和制订比较灵活。
应用场景:
一、若一个问题重复发生,能够考虑使用解释器模式。这点在数据处理和日志处理过程当中使用较多,当数据的需求方须要将数据纳为己用时,必须将数据“翻译”成本系统的数据规格;一样的道理,日志分析平台也须要根据不一样的日志格式翻译成统一的“语言”。
二、特定语法解释器。如各类解释型语言的解释器,再好比天然语言中基于语法的文本分析等。
一、解释规则多样化会致使解释器的爆炸;
二、解释器目标比较单一,行为模式比较固定,于是重要的模块中尽可能不要使用解释器模式。
''' 要开发一个自动识别谱子的吉他模拟器,达到录入谱便可按照谱发声的效果。除了发声设备外(假设已完成),最重要的就是读谱和译谱能力了。 分析其需求,整个过程大体上分能够分为两部分: 根据规则翻译谱的内容;根据翻译的内容演奏。咱们用一个解释器模型来完成这个功能。 ''' class PlayContext(): play_text = None class Expression(): def interpret(self, context): if len(context.play_text) == 0: return else: play_segs=context.play_text.split(" ") for play_seg in play_segs: pos=0 for ele in play_seg: if ele.isalpha(): pos+=1 continue break play_chord = play_seg[0:pos] play_value = play_seg[pos:] self.execute(play_chord,play_value) def execute(self,play_key,play_value): pass class NormGuitar(Expression): def execute(self, key, value): print ("Normal Guitar Playing--Chord:%s Play Tune:%s"%(key,value)) if __name__=="__main__": context = PlayContext() context.play_text = "C53231323 Em43231323 F43231323 G63231323" guitar=NormGuitar() guitar.interpret(context)
在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象以外保存这个状态。这样之后就能够将该对象恢复到原来保存的状态。在备忘录模式中,若是要保存的状态多,能够创造一个备忘录管理者角色来管理备忘录。
一、须要保存和恢复数据的相关状态场景。如保存游戏状态的场景;撤销场景,如Ctrl-Z操做;事务回滚的应用。通常状况下事务回滚有两种方式:
一是把从恢复点开始的操做都反向执行一遍;
二是直接恢复到恢复点的各类状态。
两种方式各有优缺点,要结合业务场景,决定使用哪一种模式;
二、副本监控场景。备忘录能够看成一个临时的副本监控,实现非实时和准实时的监控。
''' 打过游戏的朋友必定知道,大多数游戏都有保存进度的功能, 若是一局游戏下来,忘保存了进度,那么下次只能从上次进度点开始从新打了。 通常状况下,保存进度是要存在可持久化存储器上,本例中先以保存在内存中来模拟实现该场景的情形。 以模拟一个战斗角色为例。首先,建立游戏角色 ''' import random class GameCharacter(): vitality = 0 attack = 0 defense = 0 def displayState(self): print ('Current Values:') print ('Life:%d' % self.vitality) print ('Attack:%d' % self.attack) print ('Defence:%d' % self.defense) def initState(self,vitality,attack,defense): self.vitality = vitality self.attack = attack self.defense = defense def saveState(self): return Memento(self.vitality, self.attack, self.defense) def recoverState(self, memento): self.vitality = memento.vitality self.attack = memento.attack self.defense = memento.defense class FightCharactor(GameCharacter): def fight(self): self.vitality -= random.randint(1,10) class Memento: vitality = 0 attack = 0 defense = 0 def __init__(self, vitality, attack, defense): self.vitality = vitality self.attack = attack self.defense = defense if __name__=="__main__": game_chrctr = FightCharactor() game_chrctr.initState(100,79,60) game_chrctr.displayState() memento = game_chrctr.saveState() game_chrctr.fight() game_chrctr.displayState() game_chrctr.recoverState(memento) game_chrctr.displayState()
当一个对象内在状态改变时容许其改变行为,这个对象看起来像改变了其类。
优势:
一、状态模式的优势是结构清晰,相比于if…else…简约了很多;
二、封装性好,外部调用没必要知道内部实现细节。
应用场景:
一、行为状态改变的场景。这点在各类控制器中很是常见,同时,逻辑结构为状态转移图的场景中都很是适用。
一、在状态比较多时,子类也会很是多,不便于管理。
''' 电梯在咱们周边随处可见,电梯的控制逻辑中心是由电梯控制器实现的。电梯的控制逻辑,即便简单点设计, 把状态分红开门状态,中止状态和运行状态,操做分红开门、关门、运行、中止,那流程也是很复杂的。 首先,开门状态不能开门、运行、中止;中止状态不能关门,中止;运行状态不能开门、关门、运行。 要用一个一个if…else…实现,首先代码混乱,不易维护;二是不易扩展。至于各类设计原则什么的…… 那该如何实现?在上边的逻辑中,每一个操做仅仅是一个操做,状态切换与操做是分离的, 这也形成后来操做和状态“相互配合”的“手忙脚乱”。若是把状态抽象成一个类, 每一个状态为一个子类,每一个状态实现什么操做,不实现什么操做,仅仅在这个类中具体实现就能够了。 下面咱们实现这个逻辑。 先实现抽象的状态类: ''' class LiftState: def open(self): pass def close(self): pass def run(self): pass def stop(self): pass class OpenState(LiftState): def open(self): print ("OPEN:The door is opened...") return self def close(self): print ("OPEN:The door start to close...") print ("OPEN:The door is closed") return StopState() def run(self): print ("OPEN:Run Forbidden.") return self def stop(self): print ("OPEN:Stop Forbidden.") return self class RunState(LiftState): def open(self): print ("RUN:Open Forbidden.") return self def close(self): print ("RUN:Close Forbidden.") return self def run(self): print ("RUN:The lift is running...") return self def stop(self): print ("RUN:The lift start to stop...") print ("RUN:The lift stopped...") return StopState() class StopState(LiftState): def open(self): print ("STOP:The door is opening...") print ("STOP:The door is opened...") return OpenState() def close(self): print ("STOP:Close Forbidden") return self def run(self): print ("STOP:The lift start to run...") return RunState() def stop(self): print ("STOP:The lift is stopped.") return self class Context: lift_state="" def getState(self): return self.lift_state def setState(self,lift_state): self.lift_state=lift_state def open(self): self.setState(self.lift_state.open()) def close(self): self.setState(self.lift_state.close()) def run(self): self.setState(self.lift_state.run()) def stop(self): self.setState(self.lift_state.stop()) if __name__=="__main__": ctx = Context() ctx.setState(StopState()) ctx.open() ctx.run() ctx.close() ctx.run() ctx.stop()