一.桥接模式定义:
桥接模式即将抽象部分与实现部分脱耦,使它们可以独立变化。
抽象化(Abstraction)角色:抽象化给出的定义,并保存一个对实现化对象的引用。
修正抽象化(Refined Abstraction)角色:扩展抽象化角色,改变和修正父类对抽象化的定义。
实现化(Implementor)角色:这个角色给出实现化角色的接口,但不给出具体的实现。必须指出的是,这个接口不一定和抽象化角色的接口定义相同,实际上,这两个接口可以非常不一样。实现化角色应当只给出底层操作,而抽象化角色应当只给出基于底层操作的更高一层的操作。
二.桥接模式的实现:
我先引进一个生活中的例子,这里引用一个电视遥控器的例子,对于每一个牌子的遥控器,都有对于的遥控器来控制,这时候我们想到的设可能是:抽象一个遥控器接口,里面有待实现的开机,关机,换图这样一组功能方法。然后创建具体的遥控器类去继承这个接口,实现里面的方法。这样可以满足每个电视机都实现了自己的遥控器,对于新增了其他类型的电视机,只需要添加一个派生类就可以满足新的遥控器的派生。但是哪一天,用户要求在遥控中加入一个返回上一个频道的功能时候,就需要改变抽象出来的遥控器接口,需要向抽象类中添加一个新的方法,这样就改变了抽象类的实现。如果用户要求同时改变电视机的产品行为,和遥控器的行为方法,对于上面的设计会造成很大的改动。使用桥接模式可以很好的解决这些问题。
三.使用桥接模式:
对于上面的设计,抽象化和实现部分在一起,而桥接模式的目的就是使两者分离,根据面向对象的封装变化的原则,我们可以把实现部分的变化(也就是遥控器功能的变化)封装到另外一个类中。这样的一个思路也就是桥接模式的实现。下面我们看下是如何实现这样的思路。
首先抽象出电视机,提供遥控器改变的行为方法。
/// <summary>
/// 电视机,提供抽象方法
/// </summary>
public abstract class TV
{
public abstract void On();
public abstract void Off();
public abstract void tuneChannel();
}
创建具体的电视机,继承自抽象电视机类:
/// <summary>
/// 三星牌电视机,重写基类的抽象方法
/// </summary>
public class Samsung:TV
{
public override void On()
{
Console.WriteLine("三星牌电视机已经打开了");
}
public override void Off()
{
Console.WriteLine("三星牌电视机已经关掉了");
}
public override void tuneChannel()
{
Console.WriteLine("三星牌电视机换频道");
}
}
/// <summary>
/// 长虹牌电视机,重写基类的抽象方法
/// 提供具体的实现
/// </summary>
public class ChangHong : TV
{
public override void On()
{
Console.WriteLine("长虹牌电视机已经打开了");
}
public override void Off()
{
Console.WriteLine("长虹牌电视机已经关掉了");
}
public override void tuneChannel()
{
Console.WriteLine("长虹牌电视机换频道");
}
}
然后抽象出概览中的遥控器,扮演抽象话的角色。
/// <summary>
/// 抽象概念中的遥控器,扮演抽象化角色
/// </summary>
public abstract class RemoteControl
{
public TV implementor { get; set; }
/// <summary>
/// 开电视机
/// 这里抽象类中不再提供实现了,而是调用实现类中的实现
/// </summary>
public virtual void On()
{
implementor.On();
}
/// <summary>
/// 关电视机
/// </summary>
public virtual void Off()
{
implementor.Off();
}
/// <summary>
/// 换频道
/// </summary>
public virtual void SetChannel()
{
implementor.tuneChannel();
}
}
创建具体遥控器类:这里面,我重写了更换频道的方法,其实还可以重写其他的方法。
/// <summary>
/// 具体遥控器类
/// </summary>
public class ConcreteRemote:RemoteControl
{
/// <summary>
/// 重写更换频道方法
/// </summary>
public override void SetChannel()
{
Console.WriteLine("重写更换频道方法");
base.SetChannel();
}
}
使用:
static void Main(string[] args)
{
// 创建一个遥控器
RemoteControl remoteControl = new ConcreteRemote();
//长虹电视机
remoteControl.implementor = new ChangHong();
remoteControl.On();
remoteControl.SetChannel();
remoteControl.Off();
Console.WriteLine();
// 三星牌电视机
remoteControl.implementor = new Samsung();
remoteControl.On();
remoteControl.SetChannel();
remoteControl.Off();
Console.Read();
}
这样接实现了桥接模式的设计,遥控器的功能实现方法不是在遥控器中去实现了,而是将实现部分用来另一个电视机类去封装它,遥控器中只包含电视机类的一个引用,通过桥接模式,我们把抽象化和实现化部分分离开了,这样可以很好应对这两方面的变化。
优点:抽象接口与其实现解耦,期中的抽象和实现可以独立的进行扩展,不会影响到对方。
缺点:增加了系统的复杂度。
使用场景:
- 如果一个系统需要在构件的抽象化角色和具体化角色之间添加更多的灵活性,避免在两个层次之间建立静态的联系
- 设计要求实现化角色的任何改变不应当影响客户端,或者实现化角色的改变对客户端是完全透明的。
- 需要跨越多个平台的图形和窗口系统上
- 一个类存在两个独立变化的维度,且两个维度都需要进行扩展。