Python 代码设计模式
责任链模式 (场景:OA系统,项目审批...)
使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。
适用性:
有多个的对象可以处理一个请求,哪个对象处理该请求运行时刻自动确定。
代码示例:
流程审批,跟进需要审批的额度不同。需要的环节多少则不同
class BaseHandler(object):
_superior = None
'''处理基类'''
def submit_to_superior(self, superior): # 向上级提交
# 设置上级处理人
self._superior = superior class RequestHandlerL1(BaseHandler):
'''第一级请求处理者'''
name = "TeamLeader" def handle(self,request):
if request < 500 :
print("审批者[%s],请求金额[%s],审批结果[审批通过]"%(self.name,request))
else:
print("\033[31;1m[%s]无权审批,交给下一个审批者\033[0m" %self.name)
self._superior.handle(request) class RequestHandlerL2(BaseHandler):
'''第二级请求处理者'''
name = "DeptManager"
def handle(self,request):
if request < 5000 :
print("审批者[%s],请求金额[%s],审批结果[审批通过]"%(self.name,request))
else:
print("\033[31;1m[%s]无权审批,交给下一个审批者\033[0m" %self.name)
self._superior.handle(request) class RequestHandlerL3(BaseHandler):
'''第三级请求处理者'''
name = "CEO" def handle(self,request):
if request < 10000 :
print("审批者[%s],请求金额[%s],审批结果[审批通过]"%(self.name,request))
else:
print("\033[31;1m[%s]要太多钱了,不批\033[0m"%self.name) class RequestAPI(object):
h1 = RequestHandlerL1()
h2 = RequestHandlerL2()
h3 = RequestHandlerL3() h1.submit_to_superior(h2)
h2.submit_to_superior(h3) def __init__(self,name,amount):
self.name = name
self.amount = amount def handle(self):
'''统一请求接口'''
self.h1.handle(self.amount) if __name__ == "__main__":
r1 = RequestAPI("Alex", 50000)
r1.handle()
print(r1.__dict__)
模板方法
在模板模式(Template Pattern)中,一个抽象类公开定义了执行它的方法的方式/模板。它的子类可以按需要重写方法实现,但调用将以抽象类中定义的方式进行。这种类型的设计模式属于行为型模式。
意图:定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
主要解决:一些方法通用,却在每一个子类都重新写了这一方法。
何时使用:有一些通用的方法。
如何解决:将这些通用算法抽象出来。
关键代码:在抽象类实现,其他步骤在子类实现。
应用实例: 1、在造房子的时候,地基、走线、水管都一样,只有在建筑的后期才有加壁橱加栅栏等差异。 2、西游记里面菩萨定好的 81 难,这就是一个顶层的逻辑骨架。 3、Spirng 中对 Hibernate 的支持,将一些已经定好的方法封装起来,比如开启事务、获取 Session、关闭 Session 等,程序员不重复写那些已经规范好的代码,直接丢一个实体就可以保存。
优点: 1、封装不变部分,扩展可变部分。 2、提取公共代码,便于维护。 3、行为由父类控制,子类实现。
缺点:每一个不同的实现都需要一个子类来实现,导致类的个数增加,使得系统更加庞大。
使用场景: 1、有多个子类共有的方法,且逻辑相同。 2、重要的、复杂的方法,可以考虑作为模板方法。
class Register(object):
'''用户注册接口''' def register(self):
pass
def login(self):
pass def auth(self):
self.register()
self.login() class RegisterByQQ(Register):
'''qq注册''' def register(self):
print("---用qq注册-----") def login(self):
print('----用qq登录-----') class RegisterByWeiChat(Register):
'''微信注册''' def register(self):
print("---用微信注册-----") def login(self):
print('----用微信登录-----') if __name__ == "__main__": register1 = RegisterByQQ()
register1.auth() register2 = RegisterByWeiChat()
register2.auth()
享元模式
意图:
运用共享技术有效地支持大量细粒度的对象。
适用性:
一个应用程序使用了大量的对象。
完全由于使用大量的对象,造成很大的存储开销。
对象的大多数状态都可变为外部状态。
如果删除对象的外部状态,那么可以用相对较少的共享对象取代很多组对象。
应用程序不依赖于对象标识。由于Flyweight 对象可以被共享,对于概念上明显有别的对象,标识测试将返回真值。
# Flyweight模式,顾名思义,就是共享元数据
# 在我们面向对象设计过程中,我们常常会面临着对象实例过多的问题,如果对象实例过多这将是我们系统性能提高的一个瓶颈。
# 假设我们要设计一个星空场景,现在我们需要实例星星对象,我们可以实例每一颗星星,但随着我们实例星星对象增多整个场景就越来越慢了,
# 如果你实例了1000+颗星星要你去维护,这可是一个吃力不讨好的工作。我们必须找到一个合适的方法解决以上问题,这就是今天要介绍的享元模式(Flyweight)。 # 享元模式(Flyweight):运用共享的技术有效地支持大量细粒度的对象。
#
# 抽象享元角色(Flyweight):此角色是所有的具体享元类的超类,为这些类规定出需要实现的公共接口或抽象类。那些需要外部状态(External State)的操作可以通过方法的参数传入。抽象享元的接口使得享元变得可能,但是并不强制子类实行共享,因此并非所有的享元对象都是可以共享的。
#
# 具体享元(ConcreteFlyweight)角色:实现抽象享元角色所规定的接口。如果有内部状态的话,必须负责为内部状态提供存储空间。享元对象的内部状态必须与对象所处的周围环境无关,从而使得享元对象可以在系统内共享。有时候具体享元角色又叫做单纯具体享元角色,因为复合享元角色是由单纯具体享元角色通过复合而成的。
#
# 复合享元(UnsharableFlyweight)角色:复合享元角色所代表的对象是不可以共享的,但是一个复合享元对象可以分解成为多个本身是单纯享元对象的组合。复合享元角色又称做不可共享的享元对象。这个角色一般很少使用。
#
# 享元工厂(FlyweightFactoiy)角色:本角色负责创建和管理享元角色。本角色必须保证享元对象可以被系统适当地共享。当一个客户端对象请求一个享元对象的时候,享元工厂角色需要检查系统中是否已经有一个符合要求的享元对象,如果已经有了,享元工厂角色就应当提供这个已有的享元对象;如果系统中没有一个适当的享元对象的话,享元工厂角色就应当创建一个新的合适的享元对象。
#
# 客户端(Client)角色:本角色还需要自行存储所有享元对象的外部状态。
#
# 内部状态与外部状态:在享元对象内部并且不会随着环境改变而改变的共享部分,可以称之为享元对象的内部状态,反之随着环境改变而改变的,不可共享的状态称之为外部状态。
class FlyweightBase(object):
_instances = dict()
def __init__(self,*args,**kwargs):
#继承的子类必须初始化
raise NotImplementedError def __new__(cls, *args, **kwargs):
print(cls._instances,type(cls))
return cls._instances.setdefault(
(cls,args,tuple(kwargs.items())),
# 继承此类的子类实例化时传入的参数不同,生成不同的对象,如果参数相同。则生成为一个对象
super(FlyweightBase,cls).__new__(cls)
)
# 字典.setdefault()返回对应对应key的value,super(FlyweightBase,cls).__new__(cls) 传入参数相同则生成的对象相同 def test_data(self):
pass
class Spam(FlyweightBase):
'''精子类''' def __init__(self,a,b):
self.a = a
self.b = b def test_data(self):
print("精子准备好了",self.a,self.b)
class Egg(FlyweightBase):
'''卵类'''
def __init__(self,x,y):
self.x = x
self.y = y def test_data(self):
print("卵子准备好了",self.x,self.y) spam1 = Spam(1,'abc')
spam3 = Spam(3,'DEF')
spam2 = Spam(1,'abc')
#
egg1 = Egg(1,'abc')
egg2 = Egg(1,'abc')
print(id(spam1),id(spam2),id(spam3))
print(id(egg1),id(egg2)) spam4 = Spam(1,'abc') #egg2 = Egg(4,'abc')
# assert spam1 is spam2
# assert egg1 is not spam1
# print(id(spam1),id(spam2))
# spam2.test_data()
# egg1.test_data()
# print(egg1._instances)
# print(egg1._instances.keys())
单例模式
意图:
保证一个类仅有一个实例,并提供一个访问它的全局访问点。
适用性:
当类只能有一个实例而且客户可以从一个众所周知的访问点访问它时。
当这个唯一实例应该是通过子类化可扩展的,并且客户应该无需更改代码就能使用一个扩展的实例时。
#实现__new__方法
#并在将一个类的实例绑定到类变量_instance上,
#如果cls._instance为None说明该类还没有实例化过,实例化该类,并返回
#如果cls._instance不为None,直接返回cls._instance
class Singleton(object):
def __new__(cls, *args, **kwargs):
if not hasattr(cls,'_instance'):
orig = super(Singleton,cls)
cls._instance = orig.__new__(cls)
return cls._instance class MyClass(Singleton):
def __init__(self,name):
self.name = name a = MyClass("Alex")
b = MyClass("Jack") print(a.name)
print(b.name)
观察者模式(发布/订阅)
意图:
定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时, 所有依赖于它的对象都得到通知并被自动更新。
适用性:
当一个抽象模型有两个方面, 其中一个方面依赖于另一方面。将这二者封装在独立的对象中以使它们可以各自独立地改变和复用。
当对一个对象的改变需要同时改变其它对象, 而不知道具体有多少对象有待改变。
当一个对象必须通知其它对象,而它又不能假定其它对象是谁。换言之, 你不希望这些对象是紧密耦合的。
# 观察者(Observer)模式又名发布-订阅(Publish/Subscribe)模式
# 当我们希望一个对象的状态发生变化,那么依赖与它的所有对象都能相应变化(获得通知),那么就可以用到Observer模式, 其中的这些依赖对象就是观察者的对象,那个要发生变化的对象就是所谓’观察者’ class ObserverBase(object):
'''观察者基类''' #放哨者 def __init__(self):
self._observerd_list = [] #被通知对象
self.name = None def attach(self,observe_subject):
'''
添加要观察的对象
:param observe_subject:
:return:
'''
if observe_subject not in self._observerd_list:
self._observerd_list.append(observe_subject)
print("[%s]已经将[%s]加入观察队列..."%(self.name, observe_subject) )
def detach(self,observe_subject):
'''
解除观察关系
:param observe_subject:
:return:
'''
try:
self._observerd_list.remove(observe_subject)
print("不再观察[%s]" %observe_subject)
except ValueError:
pass def notify(self):
'''
通知所有订阅者
:return:
'''
for objserver in self._observerd_list:
objserver.update(self) class Observer(ObserverBase):
'''放哨者类:继承观察者类''' def __init__(self,name):
super(Observer,self).__init__()
self.name = name
self._msg = '' @property
def msg(self):
'''
当前状况
:return:
'''
return self._msg @msg.setter
def msg(self,content):
self._msg = content
self.notify() class GCDViewer(object):
'''
共军被观察者
'''
def update(self,observer_subject):
print("共军:收到[%s]消息[%s] "%(observer_subject.name,observer_subject.msg) ) class GMDViewer(object):
'''
国军被观察者
'''
def update(self,observer_subject):
print("国军:收到[%s]消息[%s] "%(observer_subject.name,observer_subject.msg) ) if __name__ == "__main__":
observer1 = Observer("共军放哨者")
observer2 = Observer("国军放哨者") gongjun1 = GCDViewer()
guojun1 = GMDViewer() # 共军放哨者添加了共军和国军的订阅
observer1.attach(gongjun1)
observer1.attach(guojun1) # 国军放哨者 只添加了国军的订阅
observer2.attach(guojun1) observer1.msg = "\033[32;1m敌人来了...\033[0m"
observer2.msg ="\033[31;1m前方发现敌人,请紧急撤离,不要告诉共军\033[0m"
策略模式
意图:定义一系列的算法,把它们一个个封装起来, 并且使它们可相互替换。
主要解决:在有多种算法相似的情况下,使用 if...else 所带来的复杂和难以维护。
何时使用:一个系统有许多许多类,而区分它们的只是他们直接的行为。
如何解决:将这些算法封装成一个一个的类,任意地替换。
关键代码:实现同一个接口。
应用实例: 1、诸葛亮的锦囊妙计,每一个锦囊就是一个策略。 2、旅行的出游方式,选择骑自行车、坐汽车,每一种旅行方式都是一个策略。 3、JAVA AWT 中的 LayoutManager。
优点: 1、算法可以自由切换。 2、避免使用多重条件判断。 3、扩展性良好。
缺点: 1、策略类会增多。 2、所有策略类都需要对外暴露。
使用场景: 1、如果在一个系统里面有许多类,它们之间的区别仅在于它们的行为,那么使用策略模式可以动态地让一个对象在许多行为中选择一种行为。 2、一个系统需要动态地在几种算法中选择一种。 3、如果一个对象有很多的行为,如果不用恰当的模式,这些行为就只好使用多重的条件选择语句来实现。
class TravelStrategy(object):
'''
出行策略
''' def travelAlgorithm(self):
pass class AirplaneStrategy(TravelStrategy):
def travelAlgorithm(self):
print("坐飞机出行....") class TrainStrategy(TravelStrategy):
def travelAlgorithm(self):
print("坐高铁出行....") class CarStrategy(TravelStrategy):
def travelAlgorithm(self):
print("自驾出行....") class BicycleStrategy(TravelStrategy):
def travelAlgorithm(self):
print("骑车出行....") class TravelInterface(object):
# 创建出行动作
def __init__(self,travel_strategy):
self.travel_strategy = travel_strategy # 更新出行方式
def set_strategy(self,travel_strategy):
self.travel_strategy = travel_strategy # 说走就走
def travel(self):
return self.travel_strategy.travelAlgorithm() # 坐飞机
travel = TravelInterface(AirplaneStrategy()) travel.travel() # 改开车
travel.set_strategy(CarStrategy())
travel.travel()
创造者模式
意图:
将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
适用性:
当创建复杂对象的算法应该独立于该对象的组成部分以及它们的装配方式时。
当构造过程必须允许被构造的对象有不同的表示时。
#建造者模式 #相关模式:思路和模板方法模式很像,模板方法是封装算法流程,对某些细节,提供接口由子类修改,建造者模式更为高层一点,将所有细节都交由子类实现。
# 建造者模式:将一个复杂对象的构建与他的表示分离,使得同样的构建过程可以创建不同的表示。
# 基本思想
# 某类产品的构建由很多复杂组件组成;
# 这些组件中的某些细节不同,构建出的产品表象会略有不同;
# 通过一个指挥者按照产品的创建步骤来一步步执行产品的创建;
# 当需要创建不同的产品时,只需要派生一个具体的建造者,重写相应的组件构建方法即可。 def printInfo(info):
print(info) #建造者基类
class PersonBuilder():
def BuildHead(self):
pass def BuildBody(self):
pass def BuildArm(self):
pass def BuildLeg(self):
pass #胖子
class PersonFatBuilder(PersonBuilder):
type = '胖子'
def BuildHead(self):
printInfo("构建%s的头" % self.type) def BuildBody(self):
printInfo("构建%s的身体" % self.type) def BuildArm(self):
printInfo("构建%s的手" % self.type) def BuildLeg(self):
printInfo("构建%s的脚" % self.type) #瘦子
class PersonThinBuilder(PersonBuilder):
type = '瘦子'
def BuildHead(self):
printInfo("构建%s的头" % self.type) def BuildBody(self):
printInfo("构建%s的身体" % self.type) def BuildArm(self):
printInfo("构建%s的手" % self.type) def BuildLeg(self):
printInfo("构建%s的脚" % self.type) #指挥者
class PersonDirector():
pb = None;
def __init__(self, pb):
self.pb = pb def CreatePereson(self):
self.pb.BuildHead()
self.pb.BuildBody()
self.pb.BuildArm()
self.pb.BuildLeg() def clientUI():
pb = PersonThinBuilder()
pd = PersonDirector(pb)
pd.CreatePereson() pb = PersonFatBuilder()
pd = PersonDirector(pb)
pd.CreatePereson()
return if __name__ == '__main__':
clientUI();
代理模式
意图:为其他对象提供一种代理以控制对这个对象的访问。
主要解决:在直接访问对象时带来的问题,比如说:要访问的对象在远程的机器上。在面向对象系统中,有些对象由于某些原因(比如对象创建开销很大,或者某些操作需要安全控制,或者需要进程外的访问),直接访问会给使用者或者系统结构带来很多麻烦,我们可以在访问此对象时加上一个对此对象的访问层。
何时使用:想在访问一个类时做一些控制。
如何解决:增加中间层。
关键代码:实现与被代理类组合。
应用实例: 1、Windows 里面的快捷方式。 2、猪八戒去找高翠兰结果是孙悟空变的,可以这样理解:把高翠兰的外貌抽象出来,高翠兰本人和孙悟空都实现了这个接口,猪八戒访问高翠兰的时候看不出来这个是孙悟空,所以说孙悟空是高翠兰代理类。 3、买火车票不一定在火车站买,也可以去代售点。 4、一张支票或银行存单是账户中资金的代理。支票在市场交易中用来代替现金,并提供对签发人账号上资金的控制。 5、spring aop。
优点: 1、职责清晰。 2、高扩展性。 3、智能化。
缺点: 1、由于在客户端和真实主题之间增加了代理对象,因此有些类型的代理模式可能会造成请求的处理速度变慢。 2、实现代理模式需要额外的工作,有些代理模式的实现非常复杂。
使用场景:按职责来划分,通常有以下使用场景: 1、远程代理。 2、虚拟代理。 3、Copy-on-Write 代理。 4、保护(Protect or Access)代理。 5、Cache代理。 6、防火墙(Firewall)代理。 7、同步化(Synchronization)代理。 8、智能引用(Smart Reference)代理。
#_*_coding:utf-8_*_
__author__ = 'Alex Li' #
# 代理模式
# 应用特性:需要在通信双方中间需要一些特殊的中间操作时引用,多加一个中间控制层。
# 结构特性:建立一个中间类,创建一个对象,接收一个对象,然后把两者联通起来 class sender_base:
def __init__(self):
pass def send_something(self, something):
pass class send_class(sender_base):
def __init__(self, receiver):
self.receiver = receiver def send_something(self, something):
print("SEND " + something + ' TO ' + self.receiver.name) class agent_class(sender_base): def __init__(self, receiver): self.send_obj = send_class(receiver) def send_something(self, something): self.send_obj.send_something(something) class receive_class:
def __init__(self, someone):
self.name = someone if '__main__' == __name__:
receiver = receive_class('Alex')
agent = agent_class(receiver)
agent.send_something('agentinfo') print(receiver.__class__ )
print(agent.__class__ )
外观模式:
意图:
为子系统中的一组接口提供一个一致的界面,Facade模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。
适用性:
当你要为一个复杂子系统提供一个简单接口时。子系统往往因为不断演化而变得越来越复杂。大多数模式使用时都会产生更多更小的类。这使得子系统更具可重用性,也更容易对子系统进行定制,但这也给那些不需要定制子系统的用户带来一些使用上的困难。Facade 可以提供一个简单的缺省视图,这一视图对大多数用户来说已经足够,而那些需要更多的可定制性的用户可以越过facade层。
客户程序与抽象类的实现部分之间存在着很大的依赖性。引入facade 将这个子系统与客户以及其他的子系统分离,可以提高子系统的独立性和可移植性。
当你需要构建一个层次结构的子系统时,使用facade模式定义子系统中每层的入口点。如果子系统之间是相互依赖的,你可以让它们仅通过facade进行通讯,从而简化了它们之间的依赖关系。
#外观模式(Facade),为子系统中的一组接口提供一个一致的界面,定义一个高层接口,这个接口使得这一子系统更加容易使用。
# 在以下情况下可以考虑使用外观模式:
# (1)设计初期阶段,应该有意识的将不同层分离,层与层之间建立外观模式。
# (2) 开发阶段,子系统越来越复杂,增加外观模式提供一个简单的调用接口。
# (3) 维护一个大型遗留系统的时候,可能这个系统已经非常难以维护和扩展,但又包含非常重要的功能,为其开发一个外观类,以便新系统与其交互。 # 优点编辑
# (1)实现了子系统与客户端之间的松耦合关系。
# (2)客户端屏蔽了子系统组件,减少了客户端所需处理的对象数目,并使得子系统使用起来更加容易。 def printInfo(info):
print(info) class Stock():
name = '股票'
def buy(self):
printInfo('买 '+self.name) def sell(self):
printInfo('卖 '+self.name) class ETF():
name = '指数型基金'
def buy(self):
printInfo('买 '+self.name) def sell(self):
printInfo('卖 '+self.name) class Future():
name = '期货'
def buy(self):
printInfo('买 '+self.name) def sell(self):
printInfo('卖 '+self.name) class NationDebt():
name = '国债'
def buy(self):
printInfo('买 '+self.name) def sell(self):
printInfo('卖 '+self.name) class Option():
name = '权证'
def buy(self):
printInfo('买 '+self.name) def sell(self):
printInfo('卖 '+self.name) #基金
class Fund(): def __init__(self):
self.stock = Stock()
self.etf = ETF()
self.future = Future()
self.debt = NationDebt()
self.option = Option() def buyFund(self):
self.stock.buy()
self.etf.buy()
self.debt.buy()
self.future.buy()
self.option.buy() def sellFund(self):
self.stock.sell()
self.etf.sell()
self.future.sell()
self.debt.sell()
self.option.sell() def clientUI():
myFund = Fund()
myFund.buyFund()
myFund.sellFund()
return if __name__ == '__main__':
clientUI()
组合模式
意图:
将对象组合成树形结构以表示“部分-整体”的层次结构。C o m p o s i t e 使得用户对单个对象和组合对象的使用具有一致性。
适用性:你想表示对象的部分-整体层次结构。
你希望用户忽略组合对象与单个对象的不同,用户将统一地使用组合结构中的所有对象。
# 应用组合模式的会员卡消费
#
# 那么我们就根据我们会员卡的消费,来模拟一下组合模式的实现吧!let's go!
#
# 首先:
#
# 1.我们的部件有,总店,分店,加盟店!
#
# 2.我们的部件共有的行为是:刷会员卡
#
# 3.部件之间的层次关系,也就是店面的层次关系是,总店下有分店、分店下可以拥有加盟店。
#
# 有了我们这几个必要条件后,我的要求就是目前店面搞活动当我在总店刷卡后,就可以累积相当于在所有下级店面刷卡的积分总额,设计的代码如下 class Store(object):
'''店面基类''' #添加店面
def add(self,store):
pass
#删除店面
def remove(self,store):
pass
def pay_by_card(self):
pass class BranchStore(Store):
def __init__(self,name):
self.name = name
self.my_store_list = [] def pay_by_card(self):
print("店面[%s]的积分已累加进该会员卡" %self.name)
for s in self.my_store_list:
s.pay_by_card() #添加店面
def add(self,store):
self.my_store_list.append(store)
#删除店面
def remove(self,store):
self.my_store_list.remove(store) class JoinStore(Store):
'''加盟店'''
def __init__(self,name):
self.name = name def pay_by_card(self):
print("店面[%s]的积分已累加进该会员卡" %self.name) def add(self,store):
print("无添加子店权限")
def remove(self,store):
print("无删除子店权限") if __name__ == "__main__":
store = BranchStore("朝阳总店")
branch = BranchStore("海滨分店")
join_branch = JoinStore("昌平加盟1店")
join_branch2 = JoinStore("昌平加盟2店") branch.add(join_branch)
branch.add(join_branch2) store.add(branch) store.pay_by_card()
print(store.my_store_list) # 这样在累积所有子店面积分的时候,就不需要去关心子店面的个数了,也不用关系是否是叶子节点还是组合节点了,也就是说不管是总店刷卡,还是加盟店刷卡,都可以正确有效的计算出活动积分。
#
# 什么情况下使用组合模式
#
# 引用大话设计模式的片段:“当发现需求中是体现部分与整体层次结构时,以及你希望用户可以忽略组合对象与单个对象的不同,统一地使用组合结构中的所有对象时,就应该考虑组合模式了。”
#
桥接模式
生活中的一个例子:
就拿汽车在路上行驶的来说。即有小汽车又有公共汽车,它们都不但能在市区中的公路上行驶,也能在高速公路上行驶。这你会发现,对于交通工具(汽车)有不同的类型,然而它们所行驶的环境(路)也在变化,在软件系统中就要适应两个方面的变化?怎样实现才能应对这种变化呢?
概述:
在软件系统中,某些类型由于自身的逻辑,它具有两个或多个维度的变化,那么如何应对这种“多维度的变化”?如何利用面向对象的技术来使得该类型能够轻松的沿着多个方向进行变化,而又不引入额外的复杂度?这就要使用Bridge模式。
意图:
将抽象部分与实现部分分离,使它们都可以独立的变化。
——《设计模式》GOF
效果及实现要点:
1.Bridge模式使用“对象间的组合关系”解耦了抽象和实现之间固有的绑定关系,使得抽象和实现可以沿着各自的维度来变化。
2.所谓抽象和实现沿着各自维度的变化,即“子类化”它们,得到各个子类之后,便可以任意它们,从而获得不同路上的不同汽车。
3.Bridge模式有时候类似于多继承方案,但是多继承方案往往违背了类的单一职责原则(即一个类只有一个变化的原因),复用性比较差。Bridge模式是比多继承方案更好的解决方法。
4.Bridge模式的应用一般在“两个非常强的变化维度”,有时候即使有两个变化的维度,但是某个方向的变化维度并不剧烈——换言之两个变化不会导致纵横交错的结果,并不一定要使用Bridge模式。
适用性:
在以下的情况下应当使用桥梁模式:
1.如果一个系统需要在构件的抽象化角色和具体化角色之间增加更多的灵活性,避免在两个层次之间建立静态的联系。
2.设计要求实现化角色的任何改变不应当影响客户端,或者说实现化角色的改变对客户端是完全透明的。
3.一个构件有多于一个的抽象化角色和实现化角色,系统需要它们之间进行动态耦合。
4.虽然在系统中使用继承是没有问题的,但是由于抽象化角色和具体化角色需要独立变化,设计要求需要独立管理这两者。
总结:
Bridge模式是一个非常有用的模式,也非常复杂,它很好的符合了开放-封闭原则和优先使用对象,而不是继承这两个面向对象原则
class AbstractRoad(object):
'''公路基类'''
car = None class AbstractCar(object):
'''车辆基类''' def run(self):
pass class People(object):
pass class Street(AbstractRoad):
'''市区街道''' def run(self):
self.car.run()
print("在市区街道上行驶") class SpeedWay(AbstractRoad):
'''高速公路''' def run(self):
self.car.run()
print("在高速公路上行驶") class Car(AbstractCar):
'''小汽车'''
def run(self):
print("小汽车在") class Bus(AbstractCar):
'''公共汽车'''
road = None def run(self):
print("公共汽车在") #加上人
class Man(People):
def drive(self):
print("男人开着")
self.road.run()
#加上人
class Woman(People):
def drive(self):
print("女人开着")
self.road.run()
if __name__ == "__main__":
#小汽车在高速上行驶
road1 = SpeedWay()
road1.car = Car()
road1.run() #
road2 = SpeedWay()
road2.car = Bus()
road2.run() #人开车
road3 = Street()
road3.car = Car() p1 = Man()
p1.road = road3
p1.drive()
适配器模式
意图
将一个类的接口转换成客户希望的另外一个接口。Adapter 模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
适用性:
你想使用一个已经存在的类,而它的接口不符合你的需求。
你想创建一个可以复用的类,该类可以与其他不相关的类或不可预见的类(即那些接口可能不一定兼容的类)协同工作
#适配器模式
# 将一个类的接口转换成客户希望的另外一个接口。使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
# 应用场景:希望复用一些现存的类,但是接口又与复用环境要求不一致。 def printInfo(info):
print(info) #球员类
class Player():
name = ''
def __init__(self,name):
self.name = name def Attack(self,name):
pass def Defense(self):
pass #前锋
class Forwards(Player):
def __init__(self,name):
Player.__init__(self,name) def Attack(self):
printInfo("前锋%s 进攻" % self.name) def Defense(self,name):
printInfo("前锋%s 防守" % self.name) #中锋(目标类)
class Center(Player):
def __init__(self,name):
Player.__init__(self,name) def Attack(self):
printInfo("中锋%s 进攻" % self.name) def Defense(self):
printInfo("中锋%s 防守" % self.name) #后卫
class Guards(Player):
def __init__(self,name):
Player.__init__(self,name) def Attack(self):
printInfo("后卫%s 进攻" % self.name) def Defense(self):
printInfo("后卫%s 防守" % self.name) #外籍中锋(待适配类)
#中锋
class ForeignCenter(Player):
name = ''
def __init__(self,name):
Player.__init__(self,name) def ForeignAttack(self):
printInfo("外籍中锋%s 进攻" % self.name) def ForeignDefense(self):
printInfo("外籍中锋%s 防守" % self.name) #翻译(适配类)
class Translator(Player):
foreignCenter = None
def __init__(self,name):
self.foreignCenter = ForeignCenter(name) def Attack(self):
self.foreignCenter.ForeignAttack() def Defense(self):
self.foreignCenter.ForeignDefense() def clientUI():
b = Forwards('巴蒂尔')
m = Guards('姚明')
ym = Translator('麦克格雷迪') b.Attack()
m.Defense()
ym.Attack()
ym.Defense()
return if __name__ == '__main__':
clientUI()
Python 代码设计模式的更多相关文章
- 研磨设计模式解析及python代码实现——(二)外观模式(Facade)
一.外观模式定义 为子系统中的一组接口提供一个一致的界面,使得此子系统更加容易使用. 二.书中python代码实现 class AModuleApi: def testA(self): pass cl ...
- Python与设计模式之创建型模式及实战
用Python学习一下设计模式,如果很枯燥的话,就强行能使用的就用一下.设计模式参考Python与设计模式-途索 1. 单例模式 保证一个类仅有一个实例,并提供一个访问它的全局访问点. import ...
- [转]Python与设计模式
一.创建类设计模式 前言 什么样的程序员是一个好的程序员?学会很多门编程语言,就是一个好的程序员了么?事实上,学会一门编程语言不是一件很难的事,而“学会”一门编程语言是非常难的一件事.前一个“会”强调 ...
- Python代码样例列表
扫描左上角二维码,关注公众账号 数字货币量化投资,回复“1279”,获取以下600个Python经典例子源码 ├─algorithm│ Python用户推荐系统曼哈顿算法实现.py│ ...
- 学习 27 门编程语言的长处,提升你的 Python 代码水平
Python猫注:Python 语言诞生 30 年了,如今的发展势头可谓如火如荼,这很大程度上得益于其易学易用的优秀设计,而不可否认的是,Python 从其它语言中偷师了不少.本文作者是一名资深的核心 ...
- 可爱的豆子——使用Beans思想让Python代码更易维护
title: 可爱的豆子--使用Beans思想让Python代码更易维护 toc: false comments: true date: 2016-06-19 21:43:33 tags: [Pyth ...
- if __name__== "__main__" 的意思(作用)python代码复用
if __name__== "__main__" 的意思(作用)python代码复用 转自:大步's Blog http://www.dabu.info/if-__-name__ ...
- Python 代码风格
1 原则 在开始讨论Python社区所采用的具体标准或是由其他人推荐的建议之前,考虑一些总体原则非常重要. 请记住可读性标准的目标是提升可读性.这些规则存在的目的就是为了帮助人读写代码,而不是相反. ...
- 一行python代码实现树结构
树结构是一种抽象数据类型,在计算机科学领域有着非常广泛的应用.一颗树可以简单的表示为根, 左子树, 右子树. 而左子树和右子树又可以有自己的子树.这似乎是一种比较复杂的数据结构,那么真的能像我们在标题 ...
随机推荐
- 什么是CLI、GUI
就是命令行界面command-line interface,也有人称之为字符用户界面(CUI). 通常认为,命令行界面(CLI)没有图形用户界面(GUI)那么方便用户操作. 因为,命令行界面的软件通常 ...
- Small but Funny Tricks [Remember them all!]
模数 1e9 的神奇求行列式: #include <bits/stdc++.h> using namespace std; const int maxn = 1e2, mod = 1e9; ...
- 生物信息Linux用户创建与配额设置
创建一个新用户,并配置使用. create_usr.sh: #/usr/bin/bash user=$1 password="123" useradd ${user} -g met ...
- PHP非对称加密-RSA
对称加密算法是在加密和解密时使用同一个密钥.与对称加密算法不同,非对称加密算法需要两个密钥--公开密钥(public key)和私有密钥(private key)进行加密和解密.公钥和密钥是一对,如果 ...
- python-django使用ORM模型增删改查CRUD
from weibo.models import WeiboUser as User user_obj = User.objects.get(pk=1) user_obj.pk Out[4]: 1 u ...
- C语言小练习 微型学生管理系统
很简陋,没有做输入校验,以写出来为第一目的,中间出了不少问题,尤其是结构体内字符串赋值的时候(理解不透彻),字符串比较用strcmp不能直接==判定,逻辑也很重要,不然会出现莫名其妙的问题. 涉及知识 ...
- TOMCAT 搭建
第一步:下载 软件 和 JDK 第二个:https://www.oracle.com/java/technologies/javase-jdk16-downloads.html 传输到Linux里. ...
- C#页面缓存设置
protected void Page_Load(object sender, EventArgs e) { if (!IsPostBack) { Sessioninfo(); } Session.R ...
- c#年份筛选
年份: <script type="text/javascript" src="http://www.shicishu.com/down/WdatePicker.j ...
- Scala【json字符串和json对象互相转换】
一.fastjson工具 pom依赖 <dependency> <groupId>com.alibaba</groupId> <artifactId>f ...