桥接模式是一种结构型模式,可将一个大类或一系列紧密相关的类拆分为抽象和实现两个独立的层次结构,从而能在开发时分别使用。
假如你有一个几何形状Shape
类,从它能扩展出两个子类:圆形Circle
和方形Square
。你希望对这样的类层次结构进行扩展以使其包含颜色,所以你打算创建名为红色Red
和蓝色Blue
的形状子类。但是,由于你已有两个子类,所以总共需要创建四个类才能覆盖所有组合,例如蓝色圆形BlueCircle
和红色方形RedSquare
。
在层次结构中新增形状和颜色将导致代码复杂程度指数增长。例如添加三角形状,你需要新增两个子类,也就是每种颜色一个;此后新增一种新颜色需要新增三个子类,即每种形状一个。如此以往,情况会越来越糟糕。
问题的根本原因是我们试图在两个独立的维度——形状与颜色——上扩展形状类。这在处理类继承时是很常见的问题。
桥接模式通过将继承改为组合的方式来解决这个问题。具体来说,就是抽取其中一个维度并使之成为独立的类层次,这样就可以在初始类中引用这个新层次的对象,从而使得一个类不必拥有所有的状态和行为。
根据该方法,我们可以将颜色相关的代码抽取到拥有红色
和蓝色
两个子类的颜色类中,然后在形状
类中添加一个指向某一颜色对象的引用成员变量。现在,形状类可以将所有与颜色相关的工作委派给连入的颜色对象。这样的引用就成为了形状
和颜色
之间的桥梁。此后,新增颜色将不再需要修改形状的类层次,反之亦然。
抽象部分(也被称为接口)是一些实体的高阶控制层。该层自身不完成任何具体的工作,它需要将工作委派给实现部分层(也被称为平台)。
注意,这里提到的内容与编程语言中的接口或抽象类无关。它们并不是一回事。
在实际的程序中,抽象部分是图形用户界面(GUI),而实现部分则是底层操作系统代码(API),GUI 层调用 API 层来对用户的各种操作做出响应。
一般来说,你可以在两个独立方向上扩展这种应用:
在最糟糕的情况下,程序可能会是一团乱麻,其中包含数百种条件语句,连接着代码各处不同种类的 GUI 和各种 API。
你可以将特定接口-平台的组合代码抽取到独立的类中,以在混乱中建立一些秩序。但是,你很快会发现这种类的数量很多。类层次将以指数形式增长,因为每次添加一个新的 GUI 或支持一种新的 API 都需要创建更多的类。
让我们试着用桥接模式来解决这个问题。该模式建议将类拆分为两个类层次结构:
抽象对象控制程序的外观,并将真实工作委派给连入的实现对象。不同的实现只要遵循相同的接口就可以互换,使同一 GUI 可在 Windows 和 Linux 下运行。
最后的结果是:你无需改动与 API 相关的类就可以修改 GUI 类。此外如果想支持一个新的操作系统,只需在实现部分层次中创建一个子类即可。
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798 | using System;namespace RefactoringGuru.DesignPatterns.Bridge.Conceptual{ // 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 "ConcreteImplementationA: 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); } }} |
---|
执行结果:
12345 | Abstract: Base operation with:ConcreteImplementationA: The result in platform A.ExtendedAbstraction: Extended operation with:ConcreteImplementationA: The result in platform B. |
---|
参考原文:桥接设计模式