开篇仍是引用吕振宇老师的那篇经典的文章《设计模式随笔-蜡笔与毛笔的故事》。这个真是太经典了,没有比这个例子能更好的阐明桥接模式了,这里我就直接盗来用了。html
如今市面上卖的蜡笔不少,各类型号,各类颜色种类繁多, 假如一盒蜡笔有24种颜色,那么它能涂抹出24种不一样的颜色来,蜡笔型号是固定的,若是想画出各类线条那么就要购买不一样型号的蜡笔,假如咱们要涂抹出粗,中,细三种线条,那么咱们就要买3盒粗,中,细型号的蜡笔才能知足需求,那么就是3盒*24色=72只蜡笔。假如使用毛笔来做画,咱们须要准备3只粗,中,细的毛笔和24种颜料就行了, 那么就是3只毛笔+24种颜料。使用毛笔和使用蜡笔的差异是:用毛笔只须要3+24=27,用蜡笔须要准备3*24=72. 为何会出现这么大的差异呢?仔细分析就会发现,画画的时候不只对笔的型号有要求,并且还对颜色有要求,也就是说有两个引发变化的点或者说有两个变化的维度。蜡笔的型号和颜色直接绑定在一块儿了,他们两者彻底融合(耦合)在一块儿了,他们的属性从生产出来就已经固化了(是静态的),不能被改变了。 而毛笔的型号和颜料的颜色是毫无关系(解耦),毛笔厂家生产不一样型号的毛笔,颜料厂家生产不一样颜色的颜料,两者互不相干,只有在使用的时候用户决定用什么型号的毛笔蘸什么颜色的颜料(动态设置)来做画,这个时候毛笔和颜料才动态发生关系,若是用户想使用一个型号的毛笔画不一样颜色的画,毛笔能够洗掉再蘸不一样的颜色就能够。sql
在看看蜡笔和毛笔在应对变化的优劣比较, 若是用户须要画一个加粗线条,蜡笔须要买一盒(24),毛笔只须要买一支就能够了。若是要加一种颜色,蜡笔须要增长4支(加粗,粗,中,细),而毛笔仅仅只须要增长一种颜色就够了。 从数学的角度来说蜡笔不论是颜色或者型号的变化都会造成:型号数*颜色数,毛笔倒是:型号数+颜色数。这样看来毛笔更有优点,更容易应对变化的需求。数据库
那么在软件开发的过程当中也会碰到相似的问题,怎么来解决这类问题呢?这就是咱们将要探讨的桥接模式(Brigde)。编程
桥接模式(Bridge Pattern):将抽象部分与它的实现部分分离,使它们均可以独立地变化。它是一种对象结构型模式,又称为柄体(Handle and Body)模式或接口(Interface)模式。设计模式
用于定义抽象类的接口,它通常是抽象类而不是接口,其中定义了一个Implementor(实现类接口)类型的对象并能够维护该对象,它与Implementor之间具备关联关系,它既能够包含抽象业务方法,也能够包含具体业务方法。ide
扩充由Abstraction定义的接口,一般状况下它再也不是抽象类而是具体类,它实现了在Abstraction中声明的抽象业务方法,在RefinedAbstraction中能够调用在Implementor中定义的业务方法。工具
定义实现类的接口,这个接口不必定要与Abstraction的接口彻底一致,事实上这两个接口能够彻底不一样,通常而言,Implementor接口仅提供基本操做,而Abstraction定义的接口可能会作更多更复杂的操做。Implementor接口对这些基本操做进行了声明,而具体实现交给其子类。经过关联关系,在Abstraction中不只拥有本身的方法,还能够调用到Implementor中定义的方法,使用关联关系来替代继承关系。this
具体实现Implementor接口,在不一样的ConcreteImplementor中提供基本操做的不一样实现,在程序运行时,ConcreteImplementor对象将替换其父类对象,提供给抽象类具体的业务操做方法。spa
public abstract class Implementor { public abstract void Operation(); } public abstract class Abstraction { protected Implementor implementor; public Implementor Implementor { set { this.implementor = value; } } public virtual void Operation() { implementor.Operation(); } } public class ConcreteImplementorA : Implementor { public override void Operation() { Console.WriteLine(this.GetType().Name + " Operation"); } } public class ConcreteImplementorB : Implementor { public override void Operation() { Console.WriteLine(this.GetType().Name + " Operation"); } } public class RefinedAbstraction : Abstraction { public override void Operation() { base.Operation(); } }
客户端调用:设计
static void Main(string[] args) { Abstraction abstraction = new RefinedAbstraction(); Implementor implementor = new ConcreteImplementorA(); abstraction.Implementor = implementor; abstraction.Operation(); implementor = new ConcreteImplementorB(); abstraction.Implementor = implementor; abstraction.Operation(); Console.ReadKey(); }
输出结果:
咱们分别模拟实现开头提到的蜡笔和毛笔。咱们只选择三种型号(Large,Middle,Small)和三种颜色(Red,Green, Blue).
蜡笔类代码:
public abstract class Crayon { protected string size; protected string color; protected abstract void SetSize(); protected abstract void SetColor(); public void Display() { SetSize(); SetColor(); Console.WriteLine(this.GetType().Name + ": [Size]=" + size + "[Color]=" + color); } } public abstract class LargeCrayon : Crayon { protected override void SetSize() { size = "Large"; } } public abstract class MiddleCrayon : Crayon { protected override void SetSize() { size = "Middle"; } } public abstract class SmallCrayon : Crayon { protected override void SetSize() { size = "Small"; } } public class RedLargeCrayon : LargeCrayon { protected override void SetColor() { color = "Red"; } } public class GreenLargeCrayon : LargeCrayon { protected override void SetColor() { color = "Green"; } } public class BlueLargeCrayon : LargeCrayon { protected override void SetColor() { color = "Blue"; } } public class RedMiddleCrayon : MiddleCrayon { protected override void SetColor() { color = "Red"; } } public class GreenMiddleCrayon : MiddleCrayon { protected override void SetColor() { color = "Green"; } } public class BlueMiddleCrayon : MiddleCrayon { protected override void SetColor() { color = "Blue"; } } public class RedSmallCrayon : SmallCrayon { protected override void SetColor() { color = "Red"; } } public class GreenSmallCrayon : SmallCrayon { protected override void SetColor() { color = "Green"; } } public class BlueSmallCrayon : SmallCrayon { protected override void SetColor() { color = "Blue"; } }
客户端调用:
static void Main(string[] args) { Crayon.Crayon redLargeCrayon, greenLargeCrayon, blueLargeCrayon, redMiddleCrayon, greenMiddleCrayon, blueMiddleCrayon, redSmallCrayon, greenSmallCrayon, blueSmallCrayon; redLargeCrayon = new RedLargeCrayon(); greenLargeCrayon = new GreenLargeCrayon(); blueLargeCrayon = new BlueLargeCrayon(); redMiddleCrayon = new RedMiddleCrayon(); greenMiddleCrayon = new GreenMiddleCrayon(); blueMiddleCrayon = new BlueMiddleCrayon(); redSmallCrayon = new RedSmallCrayon(); greenSmallCrayon = new GreenSmallCrayon(); blueSmallCrayon = new BlueSmallCrayon(); redLargeCrayon.Display(); greenLargeCrayon.Display(); blueLargeCrayon.Display(); redMiddleCrayon.Display(); greenMiddleCrayon.Display(); blueMiddleCrayon.Display(); redSmallCrayon.Display(); greenSmallCrayon.Display(); blueSmallCrayon.Display(); Console.ReadKey(); }
输出:
蜡笔是一种典型的多层继承结构, 型号和颜色是在继承体系中得以实现,在程序编译的时候型号和颜色就已经绑定好了,在运行时没法再动态改变,而且类很是多,若是增长型号或者颜色将很是难以维护。
毛笔类结构图
毛笔类代码:
public abstract class Brush { private Color color; protected string size; public void SetColor(Color color) { this.color = color; } protected abstract void SetSize(); public void Draw() { SetSize(); Console.WriteLine(this.GetType().Name + ": [Size]=" + this.size + "->[Color]=" + this.color.CurrentColor); } } public abstract class Color { protected string color; public string CurrentColor { get { return color; } } } public class RedColor:Color { public RedColor() { this.color = "Red"; } } public class GreenColor:Color { public GreenColor() { this.color = "Green"; } } public class BlueColor : Color { public BlueColor() { this.color = "Blue"; } } public class LargeBrush : Brush { protected override void SetSize() { this.size = "Large"; } } public class MiddleBrush : Brush { protected override void SetSize() { this.size = "Middle"; } } public class SmallBrush : Brush { protected override void SetSize() { this.size = "Small"; } }
客户端调用:
static void Main(string[] args) { Brush largeBrush, middleBrush, smallBrush; Color red, green, blue; red = new RedColor(); green = new GreenColor(); blue = new BlueColor(); largeBrush = new LargeBrush(); middleBrush = new MiddleBrush(); smallBrush = new SmallBrush(); largeBrush.SetColor(red); largeBrush.Draw(); largeBrush.SetColor(green); largeBrush.Draw(); largeBrush.SetColor(blue); largeBrush.Draw(); middleBrush.SetColor(red); middleBrush.Draw(); middleBrush.SetColor(green); middleBrush.Draw(); middleBrush.SetColor(blue); middleBrush.Draw(); smallBrush.SetColor(red); smallBrush.Draw(); smallBrush.SetColor(green); smallBrush.Draw(); smallBrush.SetColor(blue); smallBrush.Draw(); Console.ReadKey(); }
输出结果:
LargeBrush: [Size]=Large->[Color]=Red LargeBrush: [Size]=Large->[Color]=Green LargeBrush: [Size]=Large->[Color]=Blue MiddleBrush: [Size]=Middle->[Color]=Red MiddleBrush: [Size]=Middle->[Color]=Green MiddleBrush: [Size]=Middle->[Color]=Blue SmallBrush: [Size]=Small->[Color]=Red SmallBrush: [Size]=Small->[Color]=Green SmallBrush: [Size]=Small->[Color]=Blue
毛笔类之间的结构发生了一些变化,将蜡笔的深度继承关系变成了一个平行的关联关系,这样带来的好处是毛笔的型号和颜色能够在两个体系中独立的变化而互不影响。这样就下降了耦合度,提升了扩展性,和可维护性,使得类的数量也急剧减小,下降了复杂度。
某软件公司欲开发一个数据转换工具,能够将数据库中的数据转换成多种文件格式,例如txt、xml、pdf等格式,同时该工具须要支持多种不一样的数据库。试使用桥接模式对其进行设计。
可使用桥接模式作一个简单的实现以下:
public abstract class Database { public abstract string GetData(); } public abstract class Exportor { private Database database; public void SetDatabase(Database database) { this.database = database; } public void Export() { var data = this.database.GetData(); var fileType = this.GetFileType(); Console.WriteLine(this.GetType().Name + "[Database] is [" + data + "] [FileType] is [" + fileType + "]"); } protected abstract string GetFileType(); } public class SQLDatabase : Database { public override string GetData() { return "SQLDatabase"; } } public class OracalDatabase : Database { public override string GetData() { return "OracalDatabase"; } } public class SQLiteDatabase : Database { public override string GetData() { return "SQLiteDatabase"; } } public class DBaseDatabase : Database { public override string GetData() { return "DBaseDatabase"; } } public class ExcelExportor : Exportor { protected override string GetFileType() { return "Excel"; } } public class TxtExportor : Exportor { protected override string GetFileType() { return "TxT"; } } public class XmlExportor : Exportor { protected override string GetFileType() { return "XML"; } } public class PDFExportor : Exportor { protected override string GetFileType() { return "PDF"; } }
客户端调用:
static void ExecuteExport() { Exportor exportExcel, exportPdf, exportXml, exportTxt; Database sql, sqlite, dbase, oracal; sql = new SQLDatabase(); sqlite = new SQLiteDatabase(); dbase = new DBaseDatabase(); oracal = new OracalDatabase(); exportExcel = new ExcelExportor(); exportPdf = new PDFExportor(); exportTxt = new PDFExportor(); exportXml = new XmlExportor(); exportXml.SetDatabase(sql); exportXml.Export(); exportXml.SetDatabase(oracal); exportXml.Export(); }
输出:
XmlExportor[Database] is [SQLDatabase] [FileType] is [XML] XmlExportor[Database] is [OracalDatabase] [FileType] is [XML]
抽出一个泛型执行器,使客户端调用代码更优雅一点,泛型执行器的代码以下:
public interface IExportorExcutor<in T, in V> where T : Exportor where V : Database { void Execute(); } public class ExportorExcutor<T, V> : IExportorExcutor<T, V> where T : Exportor, new() where V : Database, new() { public static IExportorExcutor<T, V> Of() { return new ExportorExcutor<T, V>(); } public void Execute() { var export = new T(); var database = new V(); export.SetDatabase(database); export.Export(); } }
客户端调用代码:
static void Main(string[] args) { ExportorExcutor<ExcelExportor, SQLiteDatabase>.Of().Execute(); ExportorExcutor<ExcelExportor, OracalDatabase>.Of().Execute(); ExportorExcutor<ExcelExportor, SQLDatabase>.Of().Execute(); ExportorExcutor<ExcelExportor, DBaseDatabase>.Of().Execute(); ExportorExcutor<PDFExportor, SQLiteDatabase>.Of().Execute(); ExportorExcutor<PDFExportor, OracalDatabase>.Of().Execute(); ExportorExcutor<PDFExportor, SQLDatabase>.Of().Execute(); ExportorExcutor<PDFExportor, DBaseDatabase>.Of().Execute(); ExportorExcutor<TxtExportor, SQLiteDatabase>.Of().Execute(); ExportorExcutor<TxtExportor, OracalDatabase>.Of().Execute(); ExportorExcutor<TxtExportor, SQLDatabase>.Of().Execute(); ExportorExcutor<TxtExportor, DBaseDatabase>.Of().Execute(); ExportorExcutor<XmlExportor, SQLiteDatabase>.Of().Execute(); ExportorExcutor<XmlExportor, OracalDatabase>.Of().Execute(); ExportorExcutor<XmlExportor, SQLDatabase>.Of().Execute(); ExportorExcutor<XmlExportor, DBaseDatabase>.Of().Execute(); Console.ReadKey(); }
输出:
ExcelExportor[Database] is [SQLiteDatabase] [FileType] is [Excel] ExcelExportor[Database] is [OracalDatabase] [FileType] is [Excel] ExcelExportor[Database] is [SQLDatabase] [FileType] is [Excel] ExcelExportor[Database] is [DBaseDatabase] [FileType] is [Excel] PDFExportor[Database] is [SQLiteDatabase] [FileType] is [PDF] PDFExportor[Database] is [OracalDatabase] [FileType] is [PDF] PDFExportor[Database] is [SQLDatabase] [FileType] is [PDF] PDFExportor[Database] is [DBaseDatabase] [FileType] is [PDF] TxtExportor[Database] is [SQLiteDatabase] [FileType] is [TxT] TxtExportor[Database] is [OracalDatabase] [FileType] is [TxT] TxtExportor[Database] is [SQLDatabase] [FileType] is [TxT] TxtExportor[Database] is [DBaseDatabase] [FileType] is [TxT] XmlExportor[Database] is [SQLiteDatabase] [FileType] is [XML] XmlExportor[Database] is [OracalDatabase] [FileType] is [XML] XmlExportor[Database] is [SQLDatabase] [FileType] is [XML] XmlExportor[Database] is [DBaseDatabase] [FileType] is [XML]
桥接模式就探讨到这里。