设计模式之桥接模式
一、桥接模式:如果软件系统中某个类存在多个独立变化的维度,我们可以将这多个维度分离出来,使这些维度可以独立扩展,比如一个表示教师的类 ,他原本包含教师资格级别和所教学科这个两个维度,如果我们抽象出一个教师类,然后要实现各个级别、各个学科的教师的话 ,就需要实现教师资格级别数量(M)和教学学科数量(N)的乘积M*N个实现类,而如果我们 将教师资格级别、教学学科从教师类中抽象出来,我们只需要实现这两个抽象的所有实现类(M个教师资格级别实现类、N个教学学科实现类 ),然后在教师类中使用组合模式方式去引用这两类实现类,则只需要M+N个实现类就可以满足需求,客户端需要什么样的实现类由它自己指定,这样既减少了实现类的数量,又增强了程序的灵活性,这种设计模式我们称之为桥接模式。
二、实现思路 :将一个类中多个独立变化的纬度分别抽象出一个抽象类,把具体的变化情况作为其对应抽象的实现类,在类中保留对这些抽象类的引用,由客户端指定其具体的实现类以满足不同的需求。
三、代码举例:
A、多重继承模式下的类代码:
1、抽象教师类:
namespace Bridge.继承模式 { public abstract class Teacher { public abstract string TeachSubject { get; set; }//教学学科 public abstract string SchoolRank { get; set; }//教学学校等级 public abstract void BeginClass();//开始上课 } }
2、实现类:
namespace Bridge.继承模式 { /// <summary> /// 高中语文老师 /// </summary> public class HighchoolChineseTeacher : Teacher { public HighchoolChineseTeacher() { this.TeachSubject = "语文"; this.SchoolRank = "高中"; } public override string TeachSubject { get ; set; } public override string SchoolRank { get; set; } public override void BeginClass() { Console.WriteLine(this.SchoolRank+ "教师级别的"+ this.TeachSubject + "老师开始上" + this.TeachSubject+"课....."); } } }
namespace Bridge.继承模式 { /// <summary> /// 高中英语老师 /// </summary> public class HighchoolEnglishTeacher : Teacher { public HighchoolEnglishTeacher() { this.TeachSubject = "英语"; this.SchoolRank = "高中"; } public override string TeachSubject { get; set; } public override string SchoolRank { get; set; } public override void BeginClass() { Console.WriteLine(this.SchoolRank + "教师级别的" + this.TeachSubject + "老师开始上" + this.TeachSubject + "课....."); } } }
namespace Bridge.继承模式 { /// <summary> /// 初中语文老师 /// </summary> public class MiddlechoolChineseTeacher : Teacher { public MiddlechoolChineseTeacher() { this.TeachSubject = "语文"; this.SchoolRank = "初中"; } public override string TeachSubject { get; set; } public override string SchoolRank { get; set; } public override void BeginClass() { Console.WriteLine(this.SchoolRank + "教师级别的" + this.TeachSubject + "老师开始上" + this.TeachSubject + "课....."); } } }
namespace Bridge.继承模式 { /// <summary> /// 高初中英语老师 /// </summary> public class MiddlechoolEnglishTeacher : Teacher { public MiddlechoolEnglishTeacher() { this.TeachSubject = "英语"; this.SchoolRank = "初中"; } public override string TeachSubject { get; set; } public override string SchoolRank { get; set; } public override void BeginClass() { Console.WriteLine(this.SchoolRank + "教师级别的" + this.TeachSubject + "老师开始上" + this.TeachSubject + "课....."); } } }
namespace Bridge.继承模式 { /// <summary> /// 小学语文老师 /// </summary> public class PrimaryschoolChineseTeacher : Teacher { public PrimaryschoolChineseTeacher() { this.TeachSubject = "语文"; this.SchoolRank = "小学"; } public override string TeachSubject { get; set; } public override string SchoolRank { get; set; } public override void BeginClass() { Console.WriteLine(this.SchoolRank + "教师级别的" + this.TeachSubject + "老师开始上" + this.TeachSubject + "课....."); } } }
namespace Bridge.继承模式 { /// <summary> ///小学英语教师 /// </summary> public class PrimaryschoolEnglishTeacher : Teacher { public PrimaryschoolEnglishTeacher() { this.TeachSubject = "英语"; this.SchoolRank = "小学"; } public override string TeachSubject { get; set; } public override string SchoolRank { get; set; } public override void BeginClass() { Console.WriteLine(this.SchoolRank + "教师级别的" + this.TeachSubject + "老师开始上" + this.TeachSubject + "课....."); } } }
B、 桥接模式下的类代码:
1、学科接口:
namespace Bridge.桥接模式 { public interface ISubject { string Subject(); } }
2、教学等级接口:
namespace Bridge.桥接模式 { public interface ISchool { String Rank();//学校等级 } }
3、学科接口实现类:
namespace Bridge.桥接模式 { public class ChineseSubject : ISubject { public string Subject() { return "语文"; } } } namespace Bridge.桥接模式 { public class EnglishSubject : ISubject { public string Subject() { return "英语"; } } }
4、教学等级接口实现类:
namespace Bridge.桥接模式 { public class Middlechool : ISchool { public string Rank() { return "中学"; } } } namespace Bridge.桥接模式 { class Primaryschool:ISchool { public string Rank() { return "小学"; } } }
5、Teacher类:
namespace Bridge.桥接模式 { public class Teacher { public ISchool _school = null; public ISubject _subject = null; public void BeginClass() { Console.WriteLine(this._school.Rank() + "教师级别的" + this._subject.Subject() + "老师开始上" + this._subject.Subject() + "课....."); } } }
6、客户端调用:
{ //桥接模式与继承模式的对比: Bridge.继承模式.Teacher teacher0 = new Bridge.继承模式.PrimaryschoolChineseTeacher(); teacher0.BeginClass(); Bridge.继承模式.Teacher teacher1 = new Bridge.继承模式.MiddlechoolEnglishTeacher(); teacher1.BeginClass(); Console.WriteLine("..........以下是桥接模式代码..................."); //如果按照以上的继承方式进行设计,假如现在教师资格固定为小学、初中、高中、大学这几类,客户端分别需要这几个资格的生物老师各一名,那么就需要同时增加4个生物老师实现类。 //如果还需要这几个资格的化学老师各一名,则又需要4个化学老师实现类,以此类推,政理化史地生语数英这9大学学科都分别需要一名老师的话,那么老师实现类的数量为9*4=32名。 //万一客户端还需要研究生导师、博士生导师等教师资格的老师呢?那全部计算下来需要实现类的数量为6*9=54个Teacher实现类,这造成了实现类爆炸性的增加,这下子这程序还怎么往下写? //有没有办法能够让扩展时减少实现类的数量?答案是使用桥接模式。 Bridge.桥接模式.Teacher techer2 = new Bridge.桥接模式.Teacher(); techer2._school = new Bridge.桥接模式.HighSchool(); techer2._subject = new Bridge.桥接模式.EnglishSubject(); techer2.BeginClass(); Bridge.桥接模式.Teacher techer3 = new Bridge.桥接模式.Teacher(); techer3._school = new Bridge.桥接模式.Middlechool(); techer3._subject = new Bridge.桥接模式.ChineseSubject(); techer3.BeginClass(); //使用桥接模式将抽象和实现分离,使他们可以独立的变化:假如需要加入需要一组数学老师,我们只需要新增一个实现ISubject 接口的数学类,通过上端指定参数,就可以取得各个学校级别的数学老师 //如果按照上面的继承模式,当我们需要新增一组数学老师时,就需要分别创建一个小学、初中、高中、大学的实现类对象。使用桥接模式,假如教师资格固定为小学、初中、高中、大学、研究生导师、博士生导师6类 //学科为政理化史地生语数英这9大学学科,则需要实现类数量为6个ISchool实现类+9个ISubject实现类=15个,比继承模式中54个少了几倍。, //在以上两种模式中,如果还需要区分老师性别,继承模式中实现类的数量为2*6*9=108个,桥接模式中实现类数量为2+6+9=17个。两种模式相比,桥接模式的优点就出来了。桥接模式也有使用起来比较 //麻烦的缺点:继承模式只需要new一个实现类即可,而桥接模式需要多new几个实现类进行指定,对于客户端而言需要了解更多的细节。 Console.ReadKey(); }
7、运行结果:
四、桥接模式的优缺点及应用:该模式适用于一个类具有多维度变化的情况,易于扩展,使用灵活,但客户端需要了解更多的细节,使用较为麻烦。