设计模式深入学习---Bridge桥接模式(结构型模式)
2017-01-13 16:38
603 查看
上期我们说了 Adapter适配器模式的用法,这次我们介绍下Bridge桥接模式。在介绍桥接模式的好处之前,我们先来看一个没有用该模式的一个小案例,然后再对比用了该模式的好处。
假设,我们制作一个手机游戏。该游戏只在安卓平台下面运行。
好了,费了不少时间,终于把需要增加的内容搞出来了,现在我们的社区也非常活跃,我们的玩家可以很好的使用我们的游戏和社区。这时候,问题其实已经出现, 如果老板接着说,我们要做音乐功能,打车功能,外卖功能,又或者下一款新游戏。基于我们的整个架构,就开始变得越来越麻烦。问题就在于我们使用面向对象的继承时带来的问题,比如对象的继承关系是在编译时候就定义好了,所以无法再运行时改变从父类继承的实现,子类的实现与它的父类有非常紧密的依赖关系,以至于父类实现中的任何变化必然会导致子类发生变化。当你需要复用子类时,如果继承下来的实现不适合解决新的问题,则父类必须重写或被其他更适合的类替换,这种依赖关系限制了灵活性并最终限制了复用性。
OK,大半个篇幅说了上面的例子,其实是为了更好的展示我们的桥接模式的一个好处,其实桥接模式非常简单,它用的是合成/聚合复用原则。即优先使用对象合成/聚合,而不是类继承。我们现在多介绍下桥接模式的原理实现,什么叫合成/聚合呢? 聚合表示一种弱的"拥有"关系,体现的是A对象可以包含B对象,但B对象不是A对象的一部分;合成这是一种强"拥有"关系,体现了严格的部分和整体关系,部分和整体的生命周期一样,比如说我们的电脑配件里面有硬盘,内存,CPU,GPU等等,里面的硬盘,内存,CPU,GPU部件是整体运行的,电脑和硬盘,内存,CPU,GPU是部分和整体的关系,他们统一运行,共同开关机,并且他们生命周期是一样的,于是电脑和CPU就是合成关系,而我们在机房里面可以看到里面有很多台电脑一块玩游戏,一块写程序,所以每台电脑都可以属于一个机房,一个机房可以有多台电脑,所以电脑和机房就是聚合关系。
合成/聚合复用原则的好处是,优先使用对象的合成/聚合将有助于你保持每个类被封装,并被集中在单个任务上,这样类和类继承层次会保持较小规模,并且不太可能增长为一个庞然大物,就我们上面的例子,我们需要用的是对象的职责,而不是结构来考虑问题,所以我们重新梳理一下,我们的平台和各个平台是一个聚合关系,而游戏,社区,后面发展的各种听歌,打车,外卖功能和平台是合成关系,我们就可以把"平台"和"软件"抽象出来,让不同的平台和功能都分别继承与他们,这样要增加新的平台或者新的功能就不用影响其他类了。
好,那我们开始使用合成/聚合的桥接模式来设计一次架构。
这一次我们的运行方法是不是变得更简便了,而且大大方便了后续的添加修改,我们只需要修改或者添加指定的类,而不会对其他子类或者父类产生影响。这就是我们使用桥接模式的好处,最后我们再来总结下Bridge桥接模式的几个要点。
Bridge桥接模式使用"对象的组合关系"解耦了抽象和实现之间固有的绑定关系,使得抽象(平台)和实现(不同的功能)可以沿着各自的维度来变化。
所谓的抽象和实现沿着各自维度的变化,即"子类化"他们,比如不同的平台子类,和不同的软件功能子类。得到各个子类之后,便可以任意组合他们,从而获得不同平台上的不同类型。
Bridge桥接模式有时类似于多继承方案,但是多继承方案往往违背单一职责原则(即一个类只有一个变化的原因),复用性比较差。Bridge桥接模式是比对继承方案更好的解决办法。
Bridge桥接模式的应用一般在"两个非常强的变化维度",有时候即使只有两个变化的维度,但是某个方向的变化维度并不剧烈---换言之两个变化不会导致纵横交错的结果,
并一定要使用Bridge桥接模式。
假设,我们制作一个手机游戏。该游戏只在安卓平台下面运行。
public class AndroidGame { public void Run() { Console.WriteLine("运行安卓手机游戏"); } }现在我们老板说,为了加大市场份额,我们还要把这个游戏做到苹果平台去,然后我们在加一个苹果平台的游戏。这时我们利用之前学过的面向对象思想,应该得有一个平台的父类,让所有平台的游戏都基于这个父类,这样就可以统一运行方法了。
public class Platform { public virtual void Run() { } } public class AndroidGame:Platform { public override void Run() { Console.WriteLine("运行安卓手机游戏"); } } public class IOSGame : Platform { public override void Run() { Console.WriteLine("运行苹果手机游戏"); } }到目前为止我们还没发现任何问题,就算我们在加入WindowsPhone平台,又或者是Web网页平台,我们的程序依然还可以保持高效,简洁。这时候,我们老板说了,我们游戏做的火了,赶紧再做一个社区功能,把玩家社交,娱乐结合起来。现在我们需要再制作一个社区功能,也就是平台下面有安卓,苹果。安卓和苹果下面分别有游戏,社区。好吧,那我们现在开始更改,重新设计架构代码。
public class Platform { public virtual void Run() { } } public class Android : Platform { } public class IOS : Platform { } //安卓游戏 public class AndroidGame : Android { public override void Run() { Console.WriteLine("运行安卓平台游戏"); } } //安卓社区 public class AndroidAPP : Android { public override void Run() { Console.WriteLine("运行安卓平台社区"); } } //苹果游戏 public class IOSGame : IOS { public override void Run() { Console.WriteLine("运行苹果平台游戏"); } } //苹果社区 public class IOSAPP : IOS { public override void Run() { Console.WriteLine("运行苹果平台社区"); } }
好了,费了不少时间,终于把需要增加的内容搞出来了,现在我们的社区也非常活跃,我们的玩家可以很好的使用我们的游戏和社区。这时候,问题其实已经出现, 如果老板接着说,我们要做音乐功能,打车功能,外卖功能,又或者下一款新游戏。基于我们的整个架构,就开始变得越来越麻烦。问题就在于我们使用面向对象的继承时带来的问题,比如对象的继承关系是在编译时候就定义好了,所以无法再运行时改变从父类继承的实现,子类的实现与它的父类有非常紧密的依赖关系,以至于父类实现中的任何变化必然会导致子类发生变化。当你需要复用子类时,如果继承下来的实现不适合解决新的问题,则父类必须重写或被其他更适合的类替换,这种依赖关系限制了灵活性并最终限制了复用性。
OK,大半个篇幅说了上面的例子,其实是为了更好的展示我们的桥接模式的一个好处,其实桥接模式非常简单,它用的是合成/聚合复用原则。即优先使用对象合成/聚合,而不是类继承。我们现在多介绍下桥接模式的原理实现,什么叫合成/聚合呢? 聚合表示一种弱的"拥有"关系,体现的是A对象可以包含B对象,但B对象不是A对象的一部分;合成这是一种强"拥有"关系,体现了严格的部分和整体关系,部分和整体的生命周期一样,比如说我们的电脑配件里面有硬盘,内存,CPU,GPU等等,里面的硬盘,内存,CPU,GPU部件是整体运行的,电脑和硬盘,内存,CPU,GPU是部分和整体的关系,他们统一运行,共同开关机,并且他们生命周期是一样的,于是电脑和CPU就是合成关系,而我们在机房里面可以看到里面有很多台电脑一块玩游戏,一块写程序,所以每台电脑都可以属于一个机房,一个机房可以有多台电脑,所以电脑和机房就是聚合关系。
合成/聚合复用原则的好处是,优先使用对象的合成/聚合将有助于你保持每个类被封装,并被集中在单个任务上,这样类和类继承层次会保持较小规模,并且不太可能增长为一个庞然大物,就我们上面的例子,我们需要用的是对象的职责,而不是结构来考虑问题,所以我们重新梳理一下,我们的平台和各个平台是一个聚合关系,而游戏,社区,后面发展的各种听歌,打车,外卖功能和平台是合成关系,我们就可以把"平台"和"软件"抽象出来,让不同的平台和功能都分别继承与他们,这样要增加新的平台或者新的功能就不用影响其他类了。
好,那我们开始使用合成/聚合的桥接模式来设计一次架构。
public abstract class PlatformSoft { public abstract void Run(); } //平台游戏 public class PlatformGame : PlatformSoft { public override void Run() { Console.WriteLine("运行游戏功能"); } } //平台社区 public class PlatformAPP : PlatformSoft { public override void Run() { Console.WriteLine("运行社区功能"); } } //各个平台类 public abstract class Platform { public PlatformSoft Soft; //设置运行的软件 public void SetPlatformSoft(PlatformSoft soft) { this.Soft = soft; } //运行 public abstract void Run(); } //安卓平台 public class Android : Platform { public override void Run() { Console.Write("安卓平台"); Soft.Run(); } } //苹果平台 public class IOS : Platform { public override void Run() { Console.Write("苹果平台"); Soft.Run(); } }在Main方法中运行一下
Platform p; p = new Android(); p.SetPlatformSoft(new PlatformAPP()); p.Run(); p.SetPlatformSoft(new PlatformGame()); p.Run(); p = new IOS(); p.SetPlatformSoft(new PlatformAPP()); p.Run(); p.SetPlatformSoft(new PlatformGame()); p.Run(); Console.ReadKey();运行效果:
这一次我们的运行方法是不是变得更简便了,而且大大方便了后续的添加修改,我们只需要修改或者添加指定的类,而不会对其他子类或者父类产生影响。这就是我们使用桥接模式的好处,最后我们再来总结下Bridge桥接模式的几个要点。
Bridge桥接模式使用"对象的组合关系"解耦了抽象和实现之间固有的绑定关系,使得抽象(平台)和实现(不同的功能)可以沿着各自的维度来变化。
所谓的抽象和实现沿着各自维度的变化,即"子类化"他们,比如不同的平台子类,和不同的软件功能子类。得到各个子类之后,便可以任意组合他们,从而获得不同平台上的不同类型。
Bridge桥接模式有时类似于多继承方案,但是多继承方案往往违背单一职责原则(即一个类只有一个变化的原因),复用性比较差。Bridge桥接模式是比对继承方案更好的解决办法。
Bridge桥接模式的应用一般在"两个非常强的变化维度",有时候即使只有两个变化的维度,但是某个方向的变化维度并不剧烈---换言之两个变化不会导致纵横交错的结果,
并一定要使用Bridge桥接模式。
相关文章推荐
- C#面向对象设计模式学习笔记(7) - Bridge 桥接模式(结构型模式)
- 设计模式学习之桥接模式(Bridge,结构型模式)(15)
- 【设计模式学习笔记八】【结构型模式】【桥接模式(Bridge)】
- 设计模式学习笔记(八)——Bridge桥接模式
- 设计模式学习-Bridge(桥接)
- 设计模式入门学习 桥接Bridge模式
- 设计模式学习笔记(八)——Bridge桥接模式
- 结构型设计模式---桥接模式(Bridge)
- 设计模式(八):Bridge桥接模式 -- 结构型模式
- 设计模式学习笔记(八)——Bridge桥接模式
- 设计模式学习总结-桥接模式(Bridge Pattern)
- 设计模式之八:Bridge(桥接)—对象结构型模式
- C#面向对象设计模式纵横谈 学习笔记8 Bridge桥接(结构型模式)
- 设计模式学习笔记(四)—Bridge桥接模式
- 设计模式笔记--结构型模式之二--桥接 Bridge
- 设计模式--桥接模式Bridge(结构型)
- 设计模式学习笔记——桥接(Bridge)模式
- 设计模式学习笔记(八)——Bridge桥接
- Bridge桥接(结构型模式)——读李建忠设计模式
- 【设计模式基础】结构型模式 - 4 - 桥接(Bridge)