现有一个需求,一个游戏系统需要构建不同风格的房屋,暂不考虑其他设计模式,需要能实现在PC端、移动端....等等多个平台的构建.最简单的实现方式如下:
/// <summary> /// 房屋抽象 /// </summary> public abstract class House { /// <summary> /// 不同平台的初始化方法 /// </summary> public abstract void PlatformInit(); /// <summary> /// 绘制窗户 /// </summary> public abstract void DrowWindow(); /// <summary> /// 绘制门 /// </summary> public abstract void DrowDoor(); } /// <summary> /// PC版的现代化房屋构建过程 /// </summary> public class PCModernHouse : House { public override void DrowDoor() { } public override void DrowWindow() { } public override void PlatformInit() { //这里初始化构建PC版的现代化房屋所需要的PC平台的相关信息 } } /// <summary> /// 移动端的现代化房屋构建过程 /// </summary> public class MobileModernHouse : House { public override void DrowDoor() { } public override void DrowWindow() { } public override void PlatformInit() { //这里初始化构建移动端的现代化房屋所需要的移动端平台的相关信息 } } /// <summary> /// PC版经典房屋 /// </summary> public class PCClassicalHouse : House { public override void DrowDoor() { } public override void DrowWindow() { } public override void PlatformInit() { //这里初始化构建PC版经典房屋所需要的PC平台的相关信息 } } /// <summary> /// 移动版经典房屋 /// </summary> public class MobileClassicalHouse : House { public override void DrowDoor() { } public override void DrowWindow() { } public override void PlatformInit() { //这里初始化构建移动版经典房屋所需要的移动版平台的相关信息 } }
ok,这种设计虽然能很好的满足需求,但是这里只列举了两种平台,如果之后需要支持更多的平台,这种设计模式显然不行,因为产生的类会原来越多.随之维护的成本也越来越大.
so.分析代码,发现设计中有两个变化点,一个是House,另一个是平台,而上面的代码并没有把平台作为变化点抽离出来,所以需要将平台抽离抽来,接下来,对代码进行重构.
思考:由于House的固有逻辑,使得House具有两个维护的变化一一一个变化维度为"平台的变化",另一个变化维度为"风格的变化".那么如何解决这种维度的变化?如何利用OOP,来轻松地使得House以"平台"和"风格"两个方向变化?这就是桥接模式要解决的问题:
利用Bridge桥接模式重构后的代码如下:
#region 抽象 /// <summary> /// 房屋抽象 /// </summary> public abstract class House { protected HousePlatform _housePlatform; public House(HousePlatform housePlatform) { _housePlatform = housePlatform; } public HousePlatform HousePlatform => _housePlatform; /// <summary> /// 绘制窗户 /// </summary> public abstract void DrowWindow(); /// <summary> /// 绘制门 /// </summary> public abstract void DrowDoor(); } /// <summary> /// 平台抽象 /// </summary> public abstract class HousePlatform { public abstract HousePlatform Init(); } #endregion #region 实现 /// <summary> /// 现代化房屋 /// </summary> public class ModernHouse : House { private HousePlatform _platform; public ModernHouse(HousePlatform housePlatform) : base(housePlatform) { _platform = HousePlatform.Init(); } public override void DrowDoor() { //执行HousePlatform实例的一些方法,然后做自己的逻辑 } public override void DrowWindow() { } } /// <summary> /// 经典房屋 /// </summary> public class ClassicalHouse : House { private HousePlatform _platform; public ClassicalHouse(HousePlatform housePlatform) : base(housePlatform) { _platform = housePlatform.Init(); } public override void DrowDoor() { } public override void DrowWindow() { } } /// <summary> /// PC平台 /// </summary> public class PCPlatform : HousePlatform { public override HousePlatform Init() { //执行PC平台的初始化方法,返回一个PCPlatform对象实例供对应的房屋使用 return this.MemberwiseClone() as HousePlatform; } } /// <summary> /// 移动端平台 /// </summary> public class MobilePlatform : HousePlatform { public override HousePlatform Init() { //执行移动端平台的初始化方法,返回一个MobilePlatform对象实例供对应的房屋使用 return this.MemberwiseClone() as HousePlatform; } } #endregion
客户端调用代码如下:
public class GameSystem { public void Build() { //构建了一个基于PC平台的现代化房屋 var modernHouse = new ModernHouse(new PCPlatform()); modernHouse.DrowDoor(); modernHouse.DrowWindow(); } }
将变化点平台也分离出来,并抽象出一个接口,并通过构造函数的方式将两个变化点桥接到一起,可以理解为组合到一起,这就是桥接模式.
桥接模式使用的要点:
1、Bridge桥接模式一般是用在两个变化剧烈的维度,如上面的房屋的风格和平台的类型都是变化非常剧烈的,但如果有一个维度变化并不剧烈,则并需要使用桥接模式.
2、抽象和实现沿着各自纬度的变化,比如不同风格的房屋和不同的平台.得到各个子类之后,便可以不同的方式组合它们,便可以得到不同平台下的不同风格的房屋.
3、多继承关系,可以考虑使用Bridge模式来实现.多继承方案往往违背oop的单一职责.Bridge模式是比多继承更好的选择.
4、Bridge模式使用对象组合关系,解耦了抽象和实现之间固有的绑定关系,使得抽象(不同风格的房屋)和实现(不同的平台)可以沿着各自的维度变化.
,