Bridge 桥模式

一.意图

桥接是一种结构设计模式,允许你将一个大型类或一组密切相关的类拆分为两个独立的层级------抽象和实现------这些层级可以独立开发。

由于某些类型的固有的实现逻辑,使得它们具有两个变化的维度,乃至多个纬度的变化。

将抽象部分(业务功能)与实现部分(平台实现)分离,使它们都可以独立地变化。------《设计模式》GoF

二.问题

抽象*?* *实施?*听起来很吓人吗?保持冷静,我们来举一个简单的例子。

假设你有一个几何类,包含一对子类:和。你想扩展这个职业层级以融入颜色,所以你计划创建和塑造子职业。不过,既然你已经有两个子职业,你需要创建四个职业组合,比如和。Shape``Circle``Square``Red``Blue``BlueCircle``RedSquare

在层级中添加新的形状类型和颜色,层级会呈指数增长。例如,要添加三角形形状,你需要引入两个子类,分别对应每种颜色。之后,添加新颜色则需要创建三个子类,分别对应每种形状类型。越往后,情况越糟。

三.解决方案

这个问题是因为我们试图在两个独立维度上扩展形状类:按形态和按颜色。这是类继承中非常常见的问题。

桥接模式试图通过从继承切换到对象组合来解决这个问题。这意味着你将一个维度提取到一个独立的类层级结构中,使原始类引用新层级中的对象,而不是将所有状态和行为集中在一个类中。

按照这种方法,我们可以将与颜色相关的代码提取成一个包含两个子类的独立类:和。然后该类会获得一个指向某个颜色对象的参考字段。现在形状可以将任何与颜色相关的工作委托给关联的颜色对象。这个参考将成为两职业之间的桥梁。从现在起,添加新颜色不需要改变形状层次,反之亦然。Red``Blue``Shape``Shape``Color

抽象与实现

《火焰的火焰》这本书引入了抽象和实现这两个术语,作为桥接定义的一部分。在我看来,这些术语听起来太学术化了,反而让模式看起来比实际复杂得多。读完带有形状和颜色的简单示例后,让我们来解读《火杯》书中那些恐怖词语背后的含义。

抽象*(也* 称为接口 )是某个实体的高级控制层。这个层本身不应该做什么真正的工作。它应该将工作委派给实现 层(也称为平台)。

注意,我们不是在谈论你编程语言中的接口抽象类。这两者不是同一回事。

在谈论实际应用时,抽象可以用图形用户界面(GUI)表示,实现则可能是GUI层根据用户交互调用的底层作系统代码(API)。

一般来说,你可以将这样的应用扩展到两个独立的方向:

  • 拥有多个不同的图形界面(例如,针对普通客户或管理员定制的)。

  • 支持多个不同的API(例如,能够在Windows、Linux和macOS下启动应用)。

在最坏的情况下,这个应用可能看起来像一个巨大的意大利面碗,数百个条件句将不同类型的图形界面和代码中各处的API连接起来。

你可以通过将与特定接口-平台组合相关的代码提取到不同的类中,来为这场混乱带来秩序。不过,很快你会发现这类*课程有很多。*类层级结构将呈指数增长,因为添加新的图形界面或支持不同的 API 需要创建越来越多的类。

让我们试着用桥接模式来解决这个问题。它建议我们将类别分为两个层级:

  • 抽象:应用的图形界面层。

  • 实现:作系统的API。

抽象对象控制应用的外观,将实际工作委托给关联的实现对象。只要遵循统一界面,不同实现可以互换,使同一图形界面在Windows和Linux下都能正常工作。

因此,你可以在不涉及API相关类的情况下更改GUI类。此外,添加对另一个作系统的支持只需在实现层级中创建一个子类。

四.桥模式结构

五.桥模式适合应用场景

  1. 当你想划分和组织一个拥有多个功能变体的单体类时,可以使用桥接模式(例如,该类是否能与多个数据库服务器兼容)。

    课程越大,越难弄明白它是如何运作的,做出改变所需的时间也越长。对某一功能变体的更改可能需要在整个类别中进行调整,这常常导致错误或未能解决一些关键副作用。

    桥梁模式允许你将单体职业拆分成多个职业层级。之后,你可以独立于其他层级更改每个层级中的类。这种方法简化了代码维护,并最大限度地降低了破坏现有代码的风险。

  2. 当你需要在多个正交(独立)维度上扩展一个类时,可以使用这个模式。

    桥接建议你为每个维度提取一个独立的类层级结构。原始类将相关工作委托给属于这些层级的对象,而不是自己独自完成所有工作。

  3. 如果你需要在运行时切换实现,可以用桥接器。

    虽然是可选的,但桥接模式允许你替换抽象中的实现对象。只需给字段赋予一个新值即可。

    顺便说一句,这最后一点是很多人混淆桥牌和策略模式的主要原因。记住,模式不仅仅是某种课程结构。它也可能传达意图和正在解决的问题。

六.实现方式

  1. 识别你课堂中的正交维度。这些独立的概念可以是:抽象/平台、域/基础设施、前端/后端,或接口/实现。

  2. 查看客户端需要哪些作,并在基础抽象类中定义它们。

  3. 确定所有平台上可用的作。在通用实现界面中声明抽象所需的节点。

  4. 对于你领域内的所有平台,创建具体的实现类,但确保它们都遵循实现界面。

  5. 在抽象类中,添加实现类型的引用字段。抽象将大部分工作委托给该字段中引用的实现对象。

  6. 如果你有多个高级逻辑变体,可以通过扩展基础抽象类为每个变体创建精细抽象。

  7. 客户端代码应将实现对象传递给抽象的构造函数,使两者相互关联。之后,客户端可以不管实现,只处理抽象对象。

七.优缺点

  1. 优点:

    • 你可以创建平台无关的类和应用。

    • 客户端代码处理高级抽象。它没有暴露在平台细节上。

    • 开闭原则。你可以独立引入新的抽象和实现。

    • 单一责任原则。你可以在抽象中专注于高层逻辑,在实现中专注于平台细节。

  2. 缺点

    • 你可以把模式应用到高度内聚的类上,让代码更复杂。

八.与其他模式的关系

  • 桥接系统通常在前期设计,允许你独立开发应用的各个部分。另一方面,Adapter 通常与现有应用结合使用,使一些本不兼容的类能够良好协同工作。

  • 桥梁、国家、战略(以及某种程度上的适配器)结构非常相似。事实上,所有这些模式都基于构图,即将工作委托给其他对象。不过,它们各自解决的问题不同。模式不仅仅是用来构建代码的具体配方。它还能向其他开发者传达该模式所解决的问题。

  • 你可以用 Abstract Factory 和 Bridge。当Bridge定义的某些抽象只能与特定实现兼容时,这种配对非常有用。在这种情况下,Abstract Factory 可以封装这些关系,并对客户端代码隐藏复杂性。

  • 你可以将Builder和Bridge结合使用:Director类扮演抽象角色,而不同的构建者则作为实现。

九.示例代码

复制代码
/**
 * 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.
 */
​
class Implementation {
 public:
  virtual ~Implementation() {}
  virtual std::string OperationImplementation() const = 0;
};
​
/**
 * Each Concrete Implementation corresponds to a specific platform and
 * implements the Implementation interface using that platform's API.
 */
class ConcreteImplementationA : public Implementation {
 public:
  std::string OperationImplementation() const override {
    return "ConcreteImplementationA: Here's the result on the platform A.\n";
  }
};
class ConcreteImplementationB : public Implementation {
 public:
  std::string OperationImplementation() const override {
    return "ConcreteImplementationB: Here's the result on the platform B.\n";
  }
};
​
/**
 * 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 {
  /**
   * @var Implementation
   */
 protected:
  Implementation* implementation_;
​
 public:
  Abstraction(Implementation* implementation) : implementation_(implementation) {
  }
​
  virtual ~Abstraction() {
  }
​
  virtual std::string Operation() const {
    return "Abstraction: Base operation with:\n" +
           this->implementation_->OperationImplementation();
  }
};
/**
 * You can extend the Abstraction without changing the Implementation classes.
 */
class ExtendedAbstraction : public Abstraction {
 public:
  ExtendedAbstraction(Implementation* implementation) : Abstraction(implementation) {
  }
  std::string Operation() const override {
    return "ExtendedAbstraction: Extended operation with:\n" +
           this->implementation_->OperationImplementation();
  }
};
​
/**
 * 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.
 */
void ClientCode(const Abstraction& abstraction) {
  // ...
  std::cout << abstraction.Operation();
  // ...
}
/**
 * The client code should be able to work with any pre-configured abstraction-
 * implementation combination.
 */
​
int main() {
  Implementation* implementation = new ConcreteImplementationA;
  Abstraction* abstraction = new Abstraction(implementation);
  ClientCode(*abstraction);
  std::cout << std::endl;
  delete implementation;
  delete abstraction;
​
  implementation = new ConcreteImplementationB;
  abstraction = new ExtendedAbstraction(implementation);
  ClientCode(*abstraction);
​
  delete implementation;
  delete abstraction;
​
  return 0;
}

执行结果

复制代码
Abstraction: Base operation with:
ConcreteImplementationA: Here's the result on the platform A.
​
ExtendedAbstraction: Extended operation with:
ConcreteImplementationB: Here's the result on the platform B.
相关推荐
北辰当尹3 天前
【实习之旅】Kali虚拟机桥接模式ping通百度
java·服务器·桥接模式
sxlishaobin3 天前
设计模式之桥接模式
java·设计模式·桥接模式
葡萄月令with蒲公英4 天前
NAT模式、路由模式、桥接模式 区别对比
智能路由器·桥接模式
a3535413825 天前
设计模式-桥接模式
c++·设计模式·桥接模式
蔺太微7 天前
桥接模式(Bridge Pattern)
设计模式·桥接模式
阿闽ooo14 天前
桥接模式实战:用万能遥控器控制多品牌电视
c++·设计模式·桥接模式
大白要努力!15 天前
VMware 桥接模式完整配置手册
centos·桥接模式
sunriver200016 天前
【VMware】Ubuntu在桥接模式下没有网络图标
ubuntu·桥接模式·vmware
简单点的学玩17 天前
嵌入式程序设计模式-桥接模式
桥接模式