(一) 场景提出
桥接模式是属于结构型设计模式;结构型设计模式:关注的是对象和对象之间的关系(继承和组合),结构性设计模式都是在提倡:组合优于继承。
桥接模式
学习设计模式,需要从场景说起,下面说说一个最场景的场景。
下面是一个手机的抽象基类
public abstract class BasePhone { public int Price { get; set; } public abstract string System(); public abstract string Version(); public abstract void Call(); public abstract void Text(); }
分别有Galaxy和Iphone继承自BasePhone
public class Galaxy : 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 override void Text() { Console.WriteLine("Use OS {0}.{1}.{2} Text", this.GetType().Name, this.System(), this.Version()); } }
public class Iphone:BasePhone { public override string System() { return "ios"; } public override string Version() { return "9.3"; } public override void Call() { Console.WriteLine("Use OS {0}.{1}.{2} Call", this.GetType().Name, this.System(), this.Version()); } public override void Text() { Console.WriteLine("Use OS {0}.{1}.{2} Text", this.GetType().Name, this.System(), this.Version()); } }
看上去,上面的做法也没啥问题,现在有人买了不android要刷成苹果,或者把苹果刷成android。
/// <summary> /// 使用Android系统的iphone手机 /// </summary> 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 override void Text() { Console.WriteLine("Use OS {0}.{1}.{2} Text", this.GetType().Name, this.System(), this.Version()); } }
public class GalaxyIOS : BasePhone { public override string System() { return "IOS"; } public override string Version() { return "9.3"; } public override void Call() { Console.WriteLine("Use OS {0}.{1}.{2} Call", this.GetType().Name, this.System(), this.Version()); } public override void Text() { Console.WriteLine("Use OS {0}.{1}.{2} Text", this.GetType().Name, this.System(), this.Version()); } } }
==上面的代码,也没啥问题,都没问题。接下来继续看看,继续想想,我们上面有了四个子类:两种品牌x两种操作系统。
=====等下再来个Lumia手机,用的是WinPhone手机,等下,别人用来刷lumiya安卓机器,LumiyaIOS机器。=====等下galaxy也想玩WinPhone、、、
三种品牌x3种操作系统=9个子类。
再加个荣耀手机进来.......子类个数,想想都可怕。。。
如果加上版本号,不同操作系统,不同的品牌。子类个数就是个灾难
按照继承的方式写下去呢,,,就会出现子类爆炸。
该怎么办呢
(二)解决方案
从上面看,我们应该把变化封装,每个手机变化的就是操作系统和版本号。所以就提取出一个抽象类(或者接口)
public interface ISystem { string System(); string Version(); }
来了个Android系统,这里版本号也一起写了。
public class AndroidSystem : ISystem { public string System() { return "Android"; } public string Version() { return "6.0"; } }
public class IOSSystem : ISystem { public string System() { return "IOS"; } public string Version() { return "9.4"; } }
public class WinphoneSystem : ISystem { public string System() { return "Winphone"; } public string Version() { return "10.0"; } }
上面是一个接口,三个子类,把操作系统和版本号封装到这个ISystem里面去了。
继续改进我们的BasePhone--》BasePhoneBridge,
/// <summary> /// 抽象父类 /// </summary> public abstract class BasePhoneBridge { public int Price { get; set; } public ISystem SystemVersion { get; set; } /////这个时候,这里是不需要的了,SystemVersion啥时候初始化呢,交给外面的来做。 ///// <summary> ///// 操作系统 ///// </summary> ///// <returns></returns> //public abstract string System(); ///// <summary> ///// 系统版本 ///// </summary> ///// <returns></returns> //public abstract string Version(); /// <summary> /// 打电话 /// </summary> public abstract void Call(); /// <summary> /// 发短信 /// </summary> public abstract void Text(); }
public class GalaxyBridge : BasePhoneBridge { public override void Call() { Console.WriteLine("Use OS {0}.{1}.{2} Call", this.GetType().Name, this.SystemVersion.System(), this.SystemVersion.Version()); } public override void Text() { Console.WriteLine("Use OS {0}.{1}.{2} Text", this.GetType().Name, this.SystemVersion.System(), this.SystemVersion.Version()); } }
调用如下:因为现在把变化的都丢出去了,我们可以自己指定是啥操作系统。
ISystem android = new AndroidSystem(); ISystem ios = new IOSSystem(); ISystem winphone = new WinphoneSystem(); Console.WriteLine("******************************"); { BasePhoneBridge phone = new GalaxyBridge(); phone.SystemVersion = android; phone.Call(); phone.Text(); } { BasePhoneBridge phone = new GalaxyBridge(); phone.SystemVersion = ios; phone.Call(); phone.Text(); } { BasePhoneBridge phone = new GalaxyBridge(); phone.SystemVersion = winphone; phone.Call(); phone.Text(); }
把变化的东西移走了,交给上端,灵活性更好。
理解了上面就理解了桥接模式了,桥接模式解决了多维度变化的问题,缺点:但是上端需要知道更多的细节。
(三)使用场景
1、一个类存在两个独立变化的纬度,且这两个维度都需要进行扩展。
2、如果一个系统需要在构建抽象化的角色和具体化的角色之间增加更多的灵活性,避免两个层次之间建立静态的继承和联系,通过桥接模式可以实现。
3、减少子类个数。