设计模式(七)桥接
一、定义
将抽象部分与它的实现部分解耦,使两者都能够独立变化,桥接模式是一种结构型模式。
二、描述
包含以下四个角色:
1、Abstraction(抽象类):它是用于定义抽象类的接口,通常是抽象类而不是接口,其中定义了一个Implementor(实现类接口)类型的对象并可以维护该对象,它与Implementor之间具有关联关系,既可以包含抽象业务方法,也可以包含具体业务方法。
2、RefinedAbstratction(扩充抽象类):它扩充由Abstraction定义的接口,通常情况下他不再是抽象类而是具体类,实现了在Abstraction中声明的抽象业务方法,在RefinedAbstraction中可以调用在Implementor中定义的业务方法。
3、Implementor(实现类接口):它是定义实现类的接口,这个接口不一定要与Abstraction的接口完全一致,事实上两个接口可以完全不同。一般而言,Implementor只提供基本操作,而Abstraction定义的接口可能会做更多更复杂的操作。Implementor接口对这些基本操作进行了声明,而将具体实现交给其子类。通过关联关系,在Abstraction中不仅可以拥有自己的方法,还可以调用Implementor中定义的方法,使用关联关系来替代继承关系。
4、ConcreteImplementor(具体实现类):它具体实现Implementor接口,在不同的ConcreteImplementor中提供基本操作的不同实现,在程序运行时,ConcreteImplentor对象将替换其父类对象,提供给抽象类具体的业务操作方法。
三、例子
X公司想要开发一个跨平台的图像浏览系统,要求该系统能够显示JPG、BMP、GIF、PNG等多种格式的文件,并且能够在Windows、Linux以及Unix等多个操作系统上运行。该系统首先将各种格式的文件解析为像素矩阵(Matrix),然后将像素矩阵显示在屏幕上,在不同的操作系统中可以调用不同的绘制函数来绘制像素矩阵。该系统需要具备较好的扩展性以支持新的文件格式和操作系统。Matrix:像素矩阵类,辅助类,各种格式的图像文件最终都会被转化为像素矩阵,不同的操作系统提供不同的方式显示像素矩阵
public class Matrix
{
// 省略实现代码
}
Image:抽象图像类,充当抽象类
public abstract class Image
{
protected ImageImplementor imageImpl;
public void SetImageImplementor (ImageImplementor imageImpl)
{
this.imageImpl = imageImpl;
}
public abstract void ParstFile(string fileName);
}
JPGImage、BMPImage、GIFImage:扩充抽象类
public class JPGImage : Image
{
public override void ParstFile(string fileName)
{
// 模拟解析JPG文件并获得一个像素矩阵对象m
Matrix m = new Matrix();
imageImpl.DoPaint(m);
Console.WriteLine("{0} : 格式为JPG", fileName);
}
}
public class BMPImage : Image
{
public override void ParstFile(string fileName)
{
// 模拟解析BMP文件并获得一个像素矩阵对象m
Matrix m = new Matrix();
imageImpl.DoPaint(m);
Console.WriteLine("{0} : 格式为BMP", fileName);
}
}
public class GIFImage : Image
{
public override void ParstFile(string fileName)
{
// 模拟解析GIF文件并获得一个像素矩阵对象m
Matrix m = new Matrix();
imageImpl.DoPaint(m);
Console.WriteLine("{0} : 格式为GIF", fileName);
}
}
ImageImplementor:抽象操作系统实现类
public interface ImageImplementor
{
// 显示像素矩阵
void DoPaint(Matrix m);
}
WindowsImplementor、LinuxImplementor、UnixImplementor:具体实现类
public class WindowsImplementor : ImageImplementor
{
public void DoPaint(Matrix m)
{
// 调用Windows的绘制函数绘制像素矩阵
Console.WriteLine("在Windows系统中显示图像");
}
}
public class LinuxImplementor : ImageImplementor
{
public void DoPaint(Matrix m)
{
// 调用Linux的绘制函数绘制像素矩阵
Console.WriteLine("在Linux系统中显示图像");
}
}
public class UnixImplementor : ImageImplementor
{
public void DoPaint(Matrix m)
{
// 调用Unix的绘制函数绘制像素矩阵
Console.WriteLine("在Unix系统中显示图像");
}
}
Program:测试代码
Matrix m = new Matrix();
ImageImplementor wi = new WindowsImplementor();
Image ji = new JPGImage();
ji.SetImageImplementor(wi);
ji.ParstFile("小龙女");
Console.ReadLine();
四、总结
1、优点
(1)分离抽象接口及其实现部分,桥接模式使用“对象间的关联关系”解耦了抽象和实现之间固有的绑定关系,使得抽象和实现可以沿着各自的维度变化。
(2)取代多层继承方案,极大地减少了子类的个数。
(3)提高了系统可扩展性,在两个变化维度中任意扩展一个维度,不需要修改原有系统,符合开闭原则。
2、缺点
(1)增加了系统的理解和设计难度,需要开发者在一开始就对抽象层进行设计与编程。
(2)要求正确识别出系统中两个独立变化的维度,如何正确地识别需要一定的经验积累。