桥接模式 (Bridge Pattern) - 处理多维度变化
将抽象部分与它的实现部分分离,使它们都可以独立地变化。
结构图
- 客户端(Client):仅关心如何与抽象部分合作。但是,客户端需要将抽象对象与一个实现对象连接起来。
- 抽象部分(Abstraction):提供高层控制逻辑,依赖于完成底层实际工作的实现对象。
- 精确抽象(Refined Abstraction):提供控制逻辑的变体。与其父类一样,它们通过通用实现接口与不同的实现进行交互。
- 实现部分(Implementation):为所有具体实现声明通用接口。抽象部分仅能通过在这里声明的方法与实现对象交互。抽象部分可以列出和实现部分一样的方法,但是抽象部分通常声明一些复杂行为,这些行为依赖于多种由实现部分声明的原语操作。
- 具体实现(Concrete Implementations): 包括特定于平台的代码。
示例
using System;
namespace DesignPatterns.Bridge
{
// The Abstraction defines the interface for the "control" part of the two
// class hierarchies. It maintains a reference to an object of the
// Implementation hierarchy and delegates all of the real work to this
// object.
class Abstraction
{
protected IImplementation _implementation;
public Abstraction(IImplementation implementation)
{
this._implementation = implementation;
}
public virtual string Operation()
{
return "Abstract: Base operation with:\n" +
_implementation.OperationImplementation();
}
}
// You can extend the Abstraction without changing the Implementation
// classes.
class ExtendedAbstraction : Abstraction
{
public ExtendedAbstraction(IImplementation implementation) : base(implementation)
{
}
public override string Operation()
{
return "ExtendedAbstraction: Extended operation with:\n" +
base._implementation.OperationImplementation();
}
}
// The Implementation defines the interface for all implementation classes.
// It doesn't have to match the Abstraction's interface. In fact, the two
// interfaces can be entirely different. Typically the Implementation
// interface provides only primitive operations, while the Abstraction
// defines higher- level operations based on those primitives.
public interface IImplementation
{
string OperationImplementation();
}
// Each Concrete Implementation corresponds to a specific platform and
// implements the Implementation interface using that platform's API.
class ConcreteImplementationA : IImplementation
{
public string OperationImplementation()
{
return "ConcreteImplementationA: The result in platform A.\n";
}
}
class ConcreteImplementationB : IImplementation
{
public string OperationImplementation()
{
return "ConcreteImplementationB: The result in platform B.\n";
}
}
class Client
{
// Except for the initialization phase, where an Abstraction object gets
// linked with a specific Implementation object, the client code should
// only depend on the Abstraction class. This way the client code can
// support any abstraction-implementation combination.
public void ClientCode(Abstraction abstraction)
{
Console.Write(abstraction.Operation());
}
}
class Program
{
static void Main(string[] args)
{
Client client = new Client();
Abstraction abstraction;
// The client code should be able to work with any pre-configured
// abstraction-implementation combination.
abstraction = new Abstraction(new ConcreteImplementationA());
client.ClientCode(abstraction);
Console.WriteLine();
abstraction = new ExtendedAbstraction(new ConcreteImplementationB());
client.ClientCode(abstraction);
}
}
}
运行结果
1
2
3
4
5
Abstract: Base operation with:
ConcreteImplementationA: The result in platform A.
ExtendedAbstraction: Extended operation with:
ConcreteImplementationA: The result in platform B.
总结
在软件开发中如果一个类或一个系统有多个变化维度时,都可以尝试使用桥接模式对其进行设计。
优点
- 分离抽象接口及其实现部分。桥接模式使用“对象间的关联关系”解耦了抽象和实现之间固有的绑定关系,使得抽象和实现可以沿着各自的维度来变化。所谓抽象和实现沿着各自维度的变化,也就是说抽象和实现不再在同一个继承层次结构中,而是“子类化”它们,使它们各自都具有自己的子类,以便任何组合子类,从而获得多维度组合对象。
- 在很多情况下,桥接模式可以取代多层继承方案,多层继承方案违背了“单一职责原则”,复用性较差,且类的个数非常多,桥接模式是比多层继承方案更好的解决方法,它极大减少了子类的个数。
- 桥接模式提高了系统的可扩展性,在两个变化维度中任意扩展一个维度,都不需要修改原有系统,符合“开闭原则”。
缺点
- 桥接模式的使用会增加系统的理解与设计难度,由于关联关系建立在抽象层,要求开发者一开始就针对抽象层进行设计与编程。
- 桥接模式要求正确识别出系统中两个独立变化的维度,因此其使用范围具有一定的局限性,如何正确识别两个独立维度也需要一定的经验积累。
适用场景
- 如果一个系统需要在抽象化和具体化之间增加更多的灵活性,避免在两个层次之间建立静态的继承关系,通过桥接模式可以使它们在抽象层建立一个关联关系。
- “抽象部分”和“实现部分”可以以继承的方式独立扩展而互不影响,在程序运行时可以动态将一个抽象化子类的对象和一个实现化子类的对象进行组合,即系统需要对抽象化角色和实现化角色进行动态耦合。
- 一个类存在两个(或多个)独立变化的维度,且这两个(或多个)维度都需要独立进行扩展。
- 对于那些不希望使用继承或因为多层继承导致系统类的个数急剧增加的系统,桥接模式尤为适用。
This post is licensed under CC BY 4.0 by the author.