桥接(Bridge)是将抽象部分与实现部分分离,使它们都可以独立的变化。。
这种类型的设计模式属于结构型模式,它通过提供抽象化和实现化之间的桥接结构,来实现二者的解耦。主要解决:在有多种可能会变化的情况下,用继承会造成类剧增问题,扩展起来不灵活。这种模式涉及到一个作为桥接的接口,使得实体类的功能独立于接口实现类。这两种类型的类可被结构化改变而互不影响。
首先我们来看一个问题:现在我有一个N品牌一个M品牌的手机,两个品牌的手机都有两种功能:游戏和通讯录,我们该如何实现?
依据面向对象的理论设计,我们有两种设计思想:
实现一:先有一个品牌,多个品牌就抽象出一个品牌抽象类,对于每个功能,就都继承各自的品牌;
实现二:先有功能,多个功能就可以抽象出一个抽象功能类,对于每个手机品牌,分别去继承各个功能;
上面的设计完美的遵循了面向对象的原则,但是,问题也随之而来,如果我现在需要给每个品牌都增加一个MP3播放器功能,我们该怎么办?
对于实现一,我们需要在每个品牌下面分别增加一个MP3播放器功能;对于实现二,我们需要在手机软件下增加一个抽象的MP3播放器功能,然后各个手机品牌再分别去继承这个功能。
如果我们需要再增加一个手机品牌呢?那我们要改动的地方就越来越多了。显然这种设计似乎有问题的。就像我们上面的两种实现,如果不断地增加新的手机品牌和功能,类会越来越多。怎么解决呢?
面向对象设计中还有一个很重要的原则合成/聚合复用原则,即优先使用对象合成/聚合,而不是类继承。
合成表示一种强的拥有关系,体现了严格的部分和整体的关系,部分和整体的生命周期一样,打个比方:人有两个胳膊,胳膊和人就是部分和整体的关系,人去世了,那么胳膊也就没用了,也就是说胳膊和人的生命周期是相同的,合成关系用实心的菱形+实线来表示。
合成/聚合复用规则的好处:优先使用对象的合成/聚合将有助于你保持每个类被封装,并被集中在单个任务上。这样类和类继承层次会保持在一个较小的规模,并且不太可能增长为不可控制的庞然大物。
下面我么来看看遵循合成/聚合复用规则的实现三:
桥接模式的核心意图就是把这些实现独立出来,让它们各自的变化。这就使得每种实现的变化不会影响其它的实现,从而达到应对变化的目的。
代码实现:
//手机品牌
abstract class HandsetBrand
{
protected HandsetSoft soft;
//设置手机软件
public void SetHandsetSoft(HandsetSoft soft)
{
this.soft = soft;
}
//运行
public abstract void Run();
}
//手机品牌N
class HandsetBrandN : HandsetBrand
{
public override void Run()
{
soft.Run();
}
}
//手机品牌M
class HandsetBrandM : HandsetBrand
{
public override void Run()
{
soft.Run();
}
}
//手机品牌S
class HandsetBrandS : HandsetBrand
{
public override void Run()
{
soft.Run();
}
}
//手机软件
abstract class HandsetSoft
{
public abstract void Run();
}
//手机游戏
class HandsetGame : HandsetSoft
{
public override void Run()
{
Console.WriteLine("运行手机游戏");
}
}
//手机通讯录
class HandsetAddressList : HandsetSoft
{
public override void Run()
{
Console.WriteLine("运行手机通讯录");
}
}
//手机MP3播放
class HandsetMP3 : HandsetSoft
{
public override void Run()
{
Console.WriteLine("运行手机MP3播放");
}
}
客户端
class Program
{
static void Main(string[] args)
{
HandsetBrand ab;
ab = new HandsetBrandN();
ab.SetHandsetSoft(new HandsetGame());
ab.Run();
ab.SetHandsetSoft(new HandsetAddressList());
ab.Run();
ab = new HandsetBrandM();
ab.SetHandsetSoft(new HandsetGame());
ab.Run();
ab.SetHandsetSoft(new HandsetAddressList());
ab.Run();
Console.Read();
}
}
优点:
1、抽象和实现的分离。
2、优秀的扩展能力。
3、实现细节对客户透明。
缺点:
桥接模式的引入会增加系统的理解与设计难度,由于聚合关联关系建立在抽象层,要求开发者针对抽象进行设计与编程。
使用场景:
1、如果一个系统需要在构件的抽象化角色和具体化角色之间增加更多的灵活性,避免在两个层次之间建立静态的继承联系,通过桥接模式可以使它们在抽象层建立一个关联关系。
2、对于那些不希望使用继承或因为多层次继承导致系统类的个数急剧增加的系统,桥接模式尤为适用。
3、一个类存在两个独立变化的维度,且这两个维度都需要进行扩展,对于两个独立变化的维度,使用桥接模式再适合不过了。