1:主题拆解
①基本介绍
②苹果小米刷机场景模拟
③桥接模式的优缺点
④适用场景
⑤应用实例
⑥总结
2:基本介绍
将实现与抽象放在两个不同的层次中,使两个层次可以独立改变。
桥接模式基于类的最小设计原则,通过使用封装、聚合、继承等行为让不同的类承担不同的职责。
它的主要特点是把抽象与行为实现分离开,从而可以保持各部分的独立性以及功能扩展。
3:苹果小米刷机场景模拟
1:基础版
①定义手机抽象父类
public abstract class BasePhone{public int Price { get; set; }/// <summary>/// 操作系统/// </summary>/// <returns></returns>public abstract string System();/// <summary>/// 系统版本/// </summary>/// <returns></returns>public abstract string Version();/// <summary>/// 打电话/// </summary>public abstract void Call();}
②定义苹果手机与小米手机实现
public class iPhone : BasePhone{public override string System(){return "IOS";}public override string Version(){return "12.6";}public override void Call(){Console.WriteLine("Use OS {0}.{1}.{2} Call", this.GetType().Name, this.System(), this.Version());}}public class iXiaomi : BasePhone{public override string System(){return "Android";}public override string Version(){return "8.6";}public override void Call(){Console.WriteLine("Use OS {0}.{1}.{2} Call", this.GetType().Name, this.System(), this.Version());}}
③上端调用
BasePhone phone = new iPhone();phone.Call();BasePhone xiaomi = new Xiaomi();xiaomi.Call();
分析:上面是基于抽象工厂模式实现的苹果小米手机打电话功能。如果此时用户脑洞打开,想要刷机,例如想把iPhone刷成Android系统,或者把Xiaomi刷成IOS系统,该如何解决
2:刷机版
①定义不同系统的IPhone与xiaomi
public class iPhoneAndroid : BasePhone{public override string System(){return "Android";}public override string Version(){return "6.0";}public override void Call(){Console.WriteLine("Use OS {0}.{1}.{2} Call", this.GetType().Name, this.System(), this.Version());}}public class XiaomiIOS : BasePhone{public override string System(){return "IOS";}public override string Version(){return "12.6";}public override void Call(){Console.WriteLine("Use OS {0}.{1}.{2} Call", this.GetType().Name, this.System(), this.Version());}}
②上端调用
BasePhone phone = new iPhoneAndroid();phone.Call();BasePhone xiaomi = new XiaomiIOS();xiaomi.Call();
分析:从刷机版的实现是继承基类,继续定义新的对象。但是如果手机的系统版本不一样,或者又来了一种新的系统,利润windows系统。此方法扩展类的数量将是爆炸式的增加。
例如有3个系统,分别5个版本,3个品牌,此时类的数量个数=系统×版本×品牌=45
3:桥接模式版
①定义系统接口
public interface ISystem{string System();string Version();}
②不同系统继承,并且实现
public class AndroidSystem : ISystem{public string System(){return "Android";}public string Version(){return "8.6";}}public class IOSSystem : ISystem{public string System(){return "IOS";}public string Version(){return "10.6";}}
③添加手机的抽象父类
public abstract class BasePhoneBridge{public int Price { get; set; }public ISystem SystemVersion { get; set; }public abstract void Call();}
④苹果手机与小米手机继承父类并且实现父类抽象方法
public class iPhoneBridge : BasePhoneBridge{public override void Call(){Console.WriteLine("Use OS {0}.{1}.{2} Call", this.GetType().Name, this.SystemVersion.System(), this.SystemVersion.Version());} }public class xiaomiBridge : BasePhoneBridge{public override void Call(){Console.WriteLine("Use OS {0}.{1}.{2} Call", this.GetType().Name, this.SystemVersion.System(), this.SystemVersion.Version());}}
⑤上端调用
ISystem android = new AndroidSystem();ISystem ios = new IOSSystem();BasePhoneBridge iphone = new iPhoneBridge();iphone.SystemVersion = ios;iphone.Call();BasePhoneBridge iphone2 = new iPhoneBridge();iphone2.SystemVersion = android;iphone2.Call();BasePhoneBridge xiaomi = new xiaomiBridge();xiaomi.SystemVersion = ios;xiaomi.Call();
分析:解决多维度的变化,有一组对象,对象与对象之间变化的点很多,有多个层次的变化,例如,操作系统,Size等因素变化,变化因素太多,我们就不适合使用继承的方式,继承的方式产生的子类是爆炸式的。
桥接的方式就是把变化的点,例如操作系统,封装到System对象里,定义接口,此接口交给上端来指定。
将手机中变化的点独立出去,由于操作系统的不同会造成很多子类,我们将变化点放在一个属性中,由上端去指定这个变化的点。
例如有3个系统,分别5个版本,3个品牌,此时类的数量个数=系统+版本+品牌=11
4:桥接模式的优缺点
1:优点
①低耦合
实现了抽象和实现部分的分离,桥接模式分离了抽象部分和实现部分,从而极大的提供了系统的灵活性,让抽象部分和实现部分独立开来,分别定义接口,这有助于系统进行分层设计,从而产生更好的结构化系统。对于系统的高层部分,只需要知道抽象部分和实现部分的接口就可以了。
②取代多重继承
很多情况下桥接模式可以取代多重继承,多重继承违反了SRP(单一权责原则),复用性差,而且类的个数多,桥接模式可以有效减少子类个数
③可动态的切换实现
桥接模式提高了系统的扩展性,在两个维度中任意扩展一个维度,都不需要修改原有系统,符合开闭原则
2:缺点
①增加理解难度
桥接模式会增加系统的理解以及设计难度,由于关联关系建立在抽象层,要求开发者一开始就针对抽象层进行设计以及编程。
②需要正确识别抽象层
桥接模式要求正确识别系统中两个独立变化的维度,因此适用范围有一定局限,正确识别独立维度需要一定经验积累。
5:适用场景
①不希望或不适用使用继承的场景
②接口或抽象类不稳定的场景
③重用性要求较高的场景
④对于不希望使用继承或因为多重继承导致系统类的个数急剧增加的系统
6:应用实例
①开关
我们可以看到的开关是抽象的,不用管里面具体怎么实现;
②手机品牌与手机软件
两者间有一条聚合线,一个手机品牌可以有多个手机软件。
③会员等级权限
用户通知,消息的不同紧急程度,不同的内容,不同的发送方式,很多变化的点
7:总结
不要一涉及继承就考虑该模式,尽可能把变化的因素封装到最细、最小的逻辑单元中,避免风险扩散。当发现类的继承有n层时,可以考虑使用该模式。