动机(Motivation)
- 由于某些类型的固有的实现逻辑,使得它们具有两个变化的维度,乃至多个纬度的变化。
- 如何应对这种“多维度的变化”?如何利用面向对象技术来使得类型可以轻松地沿着两个乃至多个方向变化,而不引入额外的复杂度?
模式定义
将抽象部分(业务功能)与实现部分(平台实现)分离,使它们都可以独立地变化。
——《设计模式》GoF
要点总结
- Bridge模式使用“对象间的组合关系”解耦了抽象和实现之间固有的绑定关系,使得抽象和实现可以沿着各自的维度来变化。所谓抽象和实现沿着各自纬度的变化,即“子类化”它们。
- Bridge模式有时候类似于多继承方案,但是多继承方案往往违背单一职责原则(即一个类只有一个变化的原因),复用性比较差。Bridge模式是比多继承方案更好的解决方法。
- Bridge模式的应用一般在“两个非常强的变化维度”,有时一个类也有多于两个的变化维度,这时可以使用Bridge的扩展模式。
例子
消息类一方面需要实现业务相关
的login
,send_message
等接口。比如精简版的登录仅登录即可,完美版的登录还需要播放声音等额外功能。
另一方面也要实现平台相关
相关的play_sound
、draw_shape
等接口。
一般实现
# -*- coding: utf-8 -*-
class Massage(object):
# 业务相关接口, 不同业务版本,实现不同
def login(self, user_name, password):
pass
def send_message(self, message):
pass
def send_picture(self, picture):
pass
# 平台相关接口,不同平台实现不同
def play_sound(self):
pass
def draw_shape(self):
pass
def write_text(self):
pass
def connect(self):
pass
# ----------------平台实现-------------------
class PCMassageBase(Massage):
def play_sound(self):
print('PCMassageBase, play_sound')
def draw_shape(self):
print('PCMassageBase, draw_shape')
def write_text(self):
print('PCMassageBase, write_text')
def connect(self):
print('PCMassageBase, connect')
class MobileMassageBase(Massage):
def play_sound(self):
print('MobileMassageBase, play_sound')
def draw_shape(self):
print('MobileMassageBase, draw_shape')
def write_text(self):
print('MobileMassageBase, write_text')
def connect(self):
print('MobileMassageBase, connect')
# ------------业务抽象------------
class PCMassageLite(PCMassageBase):
# 精简版
def login(self, user_name, password):
print('PCMassageLite, login')
self.connect()
def send_message(self, message):
print('PCMassageLite, send_message')
self.write_text()
def send_picture(self, picture):
print('PCMassageLite, send_picture')
self.draw_shape()
class PCMassagePerfect(PCMassageBase):
# 完美版
def login(self, user_name, password):
print('PCMassagePerfect, login')
self.connect()
self.play_sound()
def send_message(self, message):
print('PCMassagePerfect, send_message')
self.write_text()
self.play_sound()
def send_picture(self, picture):
print('PCMassagePerfect, send_picture')
self.draw_shape()
self.play_sound()
class MobileMassageLite(MobileMassageBase):
# 精简版
def login(self, user_name, password):
print('MobileMassageLite, login')
self.connect()
def send_message(self, message):
print('MobileMassageLite, send_message')
self.write_text()
def send_picture(self, picture):
print('MobileMassageLite, send_picture')
self.draw_shape()
class MobileMassagePerfect(MobileMassageBase):
# 完美版
def login(self, user_name, password):
print('MobileMassagePerfect, login')
self.connect()
self.play_sound()
def send_message(self, message):
print('MobileMassagePerfect, send_message')
self.write_text()
self.play_sound()
def send_picture(self, picture):
print('MobileMassagePerfect, send_picture')
self.draw_shape()
self.play_sound()
if __name__ == '__main__':
pc_massage_lite = PCMassageLite()
pc_massage_lite.login('root', 123)
mobile_massage_perfect = MobileMassagePerfect()
mobile_massage_perfect.login('root', 123)
仔细阅读 ,会发现:
- 该版本有重复代码,
PCMassageLite
和MobileMassageLite
,PCMassagePerfect
和MobileMassagePerfect
除了父类不同外,其他都相同。 - 需要定义的类的个数很多。平台有m种,业务版本有n种,那么需要
1+n+m*n
个类 - 业务和平台是两个不同的变化维度,杂在Message中,耦合过高
桥接模式实现
# -*- coding: utf-8 -*-
class Massage(object):
# 业务相关接口, 不同业务版本,实现不同
def __init__(self, massage_imp):
self.massage_imp = massage_imp
def login(self, user_name, password):
pass
def send_message(self, message):
pass
def send_picture(self, picture):
pass
class MassageImp(object):
# 平台相关接口,不同平台实现不同
def play_sound(self):
pass
def draw_shape(self):
pass
def write_text(self):
pass
def connect(self):
pass
# ----------------平台实现-------------------
class PCMassageImp(MassageImp):
def play_sound(self):
print('PCMassageImp, play_sound')
def draw_shape(self):
print('PCMassageImp, draw_shape')
def write_text(self):
print('PCMassageImp, write_text')
def connect(self):
print('PCMassageImp, connect')
class MobileMassageImp(MassageImp):
def play_sound(self):
print('MobileMassageImp, play_sound')
def draw_shape(self):
print('MobileMassageImp, draw_shape')
def write_text(self):
print('MobileMassageImp, write_text')
def connect(self):
print('MobileMassageImp, connect')
# ------------业务抽象------------
class MassageLite(Massage):
def login(self, user_name, password):
print('MassageLite, login')
self.massage_imp.connect()
def send_message(self, message):
print('MassageLite, send_message')
self.massage_imp.write_text()
def send_picture(self, picture):
print('MassageLite, send_picture')
self.massage_imp.draw_shape()
class MassagePerfect(Massage):
# 完美版
def login(self, user_name, password):
print('MassagePerfect, login')
self.massage_imp.connect()
self.massage_imp.play_sound()
def send_message(self, message):
print('MassagePerfect, send_message')
self.massage_imp.write_text()
self.massage_imp.play_sound()
def send_picture(self, picture):
print('MassagePerfect, send_picture')
self.massage_imp.draw_shape()
self.massage_imp.play_sound()
if __name__ == '__main__':
pc_massage_imp = PCMassageImp()
pc_massage_lite = MassageLite(pc_massage_imp)
pc_massage_lite.login('root', 123)
print('-'*30)
mobile_massage_imp = MobileMassageImp()
mobile_massage_perfect = MassagePerfect(mobile_massage_imp)
mobile_massage_perfect.login('root', 123)
变化点主要有以下几点:
- 桥接模式将业务和平台两个维度的变化拆分为了两个类, 使它们可以独立地变化。
- 将原来的继承,改为了组合。原先
PCMassageLite
通过继承PCMassageBase
在login
接口中访问对应的self.connect()
。
桥接模式MassageLite
,通过组合在login
接口中访问对应的self.massage_imp.connect()
- 需要定义的类的个数大幅度减少。平台有m种,业务版本有n种,那么需要
2+n+m
个类
网友评论