设计模式—桥接模式
前言
这里以电视遥控器为例子引出桥接模式,首先每个牌子的电视都有一个遥控器,可以设计吧遥控器作为一个抽象类,抽象类中提供遥控器的所有实现,其他具体电视品牌的遥控器都继承这个抽象类
这样的实现使得每个不同型号的电视都有自己的遥控器实现,这样的设计对于电视剧品牌的改变可以很好的应对,只要添加一个派生类就可以了。但是随着时间的推移,用户需要改变遥控器的功能,如:用户可能需要添加一个返回上个台的功能,这是就需要修改抽象类了,这样就违反了设计原则,如果用户同时改变电视剧的品牌型号和遥控器功能时,此时的设计就更麻烦了,而使用桥接模式可以很好的解决问题
桥接模式介绍
桥接模式即将抽象部分与实现部分脱耦,使它们可以独立改变。对于上面的问题,抽象化也就是RemoteControl类,实现部分就是on(),off(),nextchannel(),这样的方法。上面设计中抽象化和实现部分在一起,桥接模式的目的就是使两者分开,我们把实现部分的变化封装到另外一个类中,这样一个思路就是桥接模式的实现
1)实际例子
抽象化部分代码
//注释:里面方法定义成virtual 以方便如果有类继承此类时可以任意重写其中的方法 /// <summary> /// 抽象概念中的遥控器,扮演抽象化角色 /// </summary> public class RemoteControl { private TV implementor; public TV Implementor { get { return implementor; } set { implementor = value; } } //public virtual void MdadCity() //{ // implementor.MadeCity(); //} /// <summary> /// 开电视机,这里抽象类中不再提供实现了,而是调用实现类中的实现 /// </summary> public virtual void On() { implementor.On(); } /// <summary> /// 关电视机 /// </summary> public virtual void Off() { implementor.Off(); } /// <summary> /// 换频道 /// </summary> public virtual void RuneChannel() { implementor.RuneChannel(); } } /// <summary> /// 具体遥控器 /// </summary> public class ConcreteRemote : RemoteControl { public override void RuneChannel() { Console.WriteLine("---------------------"); base.RuneChannel(); Console.WriteLine("---------------------"); } }
实现方法的部分代码我们用另外一个抽象类TV封装了遥控器的功能变化,具体实现交给具体型号电视去完成
//注释:定义成抽象类,如果有公共的方法可以在该抽象类中进行实习,如果是接口的话有些公共的方法就不能复用了 /// <summary> /// 电视机,提供抽象方法 /// </summary> public abstract class TV { //public void MadeCity() //{ // Console.WriteLine("made in china"); //} public abstract void On(); public abstract void Off(); public abstract void RuneChannel(); } /// <summary> /// 长虹牌电视机,重写基类的抽象方法 /// 提供具体的实现 /// </summary> public class ChangHong : TV { public override void On() { Console.WriteLine("长虹牌电视机打开"); } public override void Off() { Console.WriteLine("长虹牌电视机关闭"); } public override void RuneChannel() { Console.WriteLine("长虹牌电视机换台"); } } /// <summary> /// 三星牌电视机,重写基类的抽象方法 /// </summary> public class SanXing : TV { public override void On() { Console.WriteLine("三星牌电视机打开"); } public override void Off() { Console.WriteLine("三星牌电视机关闭"); } public override void RuneChannel() { Console.WriteLine("三星牌电视机换台"); } }
客户端调用时
static void Main1(string[] args) { RemoteControl remoteControl = new ConcreteRemote(); remoteControl.Implementor = new ChangHong(); remoteControl.On(); remoteControl.RuneChannel(); remoteControl.Off(); Console.WriteLine(); remoteControl.Implementor = new SanXing(); remoteControl.On(); remoteControl.RuneChannel(); remoteControl.Off(); Console.Read(); }
运行结果:
上面打代码实现中,遥控器的实现方法不再遥控器抽象类中实现了,而是把实现部分用另一个电视类去封装,遥控器中只包含电视剧类的引用。通过桥接模式,我们把抽象化和实现部分代码分离,这样就可以很好的应对这两个方面的变化了。
2)桥接模式介绍
3)桥接模式分析
优点:抽象接口与其实现解耦
抽象和实现可以独立扩展,不会影响对方
缺点:增加了系统的复杂度
4)使用场景
如果一个系统需要在构件的抽象化角色和具体化角色之间添加更多的灵活性,避免在两个层次之间建立静态的联系
设计要求实现化角色的任何改变不应担影响客户端,或者实现化角色的改变对客户端是完全透明的
需要跨越多个平台的图形和窗口系统上
一个类存在两个对立变化的纬度,且两个纬度都需要进行扩展
5)实际例子
桥接模式经常用于具体的系统开发中,对于三层架构中就应用了桥接模式,三层架构中的业务逻辑层bll中通过桥接模式与数据库操作层解耦,其实现方式就是在bll层中引用了dal层中一个引用,这样数据操作的实现可以在不改变客户端代码的情况下动态进行更换了
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace ConsoleApplication1 { // BLL 层 public class BusinessObject { private DataAccess dataAccess; private string city; public BusinessObject(string city) { this.city = city; } public DataAccess DataAccess { get { return dataAccess; } set { dataAccess = value; } } public virtual void Add(string name) { dataAccess.AddRecord(name); } public virtual void Delete(string name) { dataAccess.DeleteRecord(name); } public virtual void Update(string name) { dataAccess.UpdateRecord(name); } public virtual string Get(int index) { return dataAccess.GetRecord(index); } public virtual void ShowAll() { Console.WriteLine(); Console.WriteLine("{0}的顾客有:", city); dataAccess.ShowAllRecords(); } } public class CustomersBusinessObject : BusinessObject { public CustomersBusinessObject(string city) : base(city) { } public override void ShowAll() { Console.WriteLine("----------"); base.ShowAll(); Console.WriteLine("___________"); } } /// <summary> /// 相当于三层架构中数据访问层(DAL) /// </summary> public abstract class DataAccess { // 对记录的增删改查操作 public abstract void AddRecord(string name); public abstract void DeleteRecord(string name); public abstract void UpdateRecord(string name); public abstract string GetRecord(int index); public abstract void ShowAllRecords(); } public class CustomersDataAccess : DataAccess { private List<string> customers = new List<string>(); public CustomersDataAccess() { customers.Add("Learning Hard"); customers.Add("张三"); customers.Add("李四"); customers.Add("王五"); } public override void AddRecord(string name) { customers.Add(name); } public override void DeleteRecord(string name) { customers.Remove(name); } public override void UpdateRecord(string updatename) { customers[0] = updatename; } public override string GetRecord(int index) { return customers[index]; } public override void ShowAllRecords() { foreach (string name in customers) { Console.WriteLine(" " + name); } } } }
客户端调用:
// 类似Web应用程序 static void Main(string[] args) { BusinessObject customers = new CustomersBusinessObject("shanghai"); customers.DataAccess = new CustomersDataAccess(); customers.Add("小六"); Console.WriteLine("增加了一位成员的结果:"); customers.ShowAll(); customers.Delete("王五"); Console.WriteLine("删除了一位成员的结果:"); customers.ShowAll(); customers.Update("Learning_Hard"); Console.WriteLine("更新了一位成员的结果:"); customers.ShowAll(); Console.Read(); }
运行结果: