介绍
桥接模式(Bridge):将抽象部分与它的实现部分分离,使它们可以独立地变化。
抽象与它的实现分离指的是抽象类和它的派生类用来实现自己的对象。
结构图
角色:
Abstraction:抽象化角色。它的主要职责是定义该角色的行为,同时保存一个对实现角色的引用,该角色一般是抽象类
Implementor:实现化角色。它是接口或者抽象类,定义角色必须的行为和属性
RefineAbstraction:修正抽象化角色。它引用实现角色对抽象化角色进行修正
ConcreteImplementor:具体实现化角色。它实现接口或抽象类定义的方法和属性。
桥接模式(桥梁模式)中的几个名词比较拗口,但是只要记住一句话:抽象角色引用实现角色,或者说抽象角色的部分实现是由实现角色完成的。
基本代码
客户端代码
static void Main(string[] args)
{
Abstraction ab = new RefinedAbstraction();
ab.SetImplementor(new ConcreteImplementorA());
ab.Operation();
ab.SetImplementor(new ConcreteImplementorB());
ab.Operation();
Console.Read();
}
Implementor类
abstract class Implementor
{
public abstract void Operation();
}
ConcreteImplementorA和ConcreteImplementorB等派生类
class ConcreteImplementorA : Implementor
{
public override void Operation()
{
Console.WriteLine("具体实现A的方法执行");
}
}
class ConcreteImplementorB : Implementor
{
public override void Operation()
{
Console.WriteLine("具体实现B的方法执行");
}
}
Abstraction 类
class Abstraction
{
protected Implementor implementor;
public void SetImplementor(Implementor implementor)
{
this.implementor = implementor;
}
public virtual void Operation()
{
implementor.Operation();
}
}
RefinedAbstraction类
class RefinedAbstraction : Abstraction
{
public override void Operation()
{
implementor.Operation();
}
}
例子
手机品牌M中有游戏“魂斗罗”而把“魂斗罗”安装在手机品牌N上不能运行,如何解决这一问题呢?
代码结构图
代码实现
客户端代码
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();
}
手机软件
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("运行手机通讯录");
}
}
手机品牌类
abstract class HandsetBrand
{
protected HandsetSoft soft;
//设置手机软件
public void SetHandsetSoft(HandsetSoft soft) //品牌需要关注软件,所以可在机器中安装软件(设置手机软件),以备运行
{
this.soft = soft;
}
//运行
public abstract void Run();
}
品牌N 品牌M具体类
//手机品牌N
class HandsetBrandN : HandsetBrand
{
public override void Run()
{
soft.Run();
}
}
//手机品牌M
class HandsetBrandM : HandsetBrand
{
public override void Run()
{
soft.Run();
}
}
如果需要增加一个功能,,例如MP3音乐播放功能,那么只要增加这个类就行了,不会用影响其他任何类。类的个数增加也只是一个
class HandsetMP3 : HandsetSoft
{
public override void Run()
{
Console.WriteLine("运行MP3播放");
}
}
如果此时还需要在增加一个品牌,那么只需要增加一个品牌的子类就可以了。个数也是一个,不会影响其他类的改动
class HandsetBrandS : HandsetBrand
{
public override void Run()
{
soft.Run();
}
}
桥接模式的优点
1.抽象和分离。这也是桥接模式的看主要特点,它完全是为了解决继承的缺点而提炼出的设计模式。在该模式下,实现可以不受抽象的约束,不用再绑定一个固定的抽象层次上。
2.优秀的扩充能力。增加实现、增加抽象都没有问题,只要对外暴露的接口层允许这样的变化,我们已经把变化的可能性减到最小
3.实现细节对客户透明。客户不关心细节的实现,它已经由抽象层通过聚合关系完成封装。
桥接模式的缺点
1.会增加系统的理解与设计难度,由于关联关系建立在抽象层,要求开发者一开始就针对抽象层进行设计与编程
2.正确识别出系统中两个独立变化的维度不是一件容易的事情
适用场景
1.不希望或不使用继承的场景例如 继承层次过度、无法更细化设计颗粒等场景,需要考虑使用桥接模式
2.接口或抽象类不稳定的场景
例如接口不稳定还想通过实现或继承来实现业务需求,那是得不偿失的,也是比较失败的做法。
3.重要性要求较高的场景
设计的颗粒度越细,则被重用的可能性越大,而采用继承则受父类的限制,不可能出现太细的颗粒度