桥接模式(Bridge Pattern)是用于把抽象化与实现化解耦,使得二者可以独立变化。这种类型的设计模式属于结构型模式,它通过提供抽象化和实现化之间的桥接结构,来实现二者的解耦。
这种模式涉及到一个作为桥接的接口,使得实体类的功能独立于接口实现类。这两种类型的类可被结构化改变而互不影响。

意图

将抽象部分与实现部分分离,使它们都可以独立的变化。

主要解决

在有多种可能会变化的情况下,用继承会造成类爆炸问题,扩展起来不灵活。

何时使用

实现系统可能有多个角度分类,每一种角度都可能变化。

如何解决

把这种多角度分类分离出来,让它们独立变化,减少它们之间耦合。

应用实例

  1. 猪八戒从天蓬元帅转世投胎到猪,转世投胎的机制将尘世划分为两个等级,即:灵魂和肉体,前者相当于抽象化,后者相当于实现化。生灵通过功能的委派,调用肉体对象的功能,使得生灵可以动态地选择。
  2. 使用不同粗细的笔和不同颜色的颜料可以画出粗细、颜色两个维度不同的图画,绘画需要抽象的笔和颜料,具体使用多粗的笔、什么颜料由实现决定,动态选择

优点

  1. 抽象和实现的分离。
  2. 优秀的扩展能力。
  3. 实现细节对客户透明。

缺点

桥接模式的引入会增加系统的理解与设计难度,由于聚合关联关系建立在抽象层,要求开发者针对抽象进行设计与编程。

使用场景

  1. 如果一个系统需要在构件的抽象化角色和具体化角色之间增加更多的灵活性,避免在两个层次之间建立静态的继承联系,通过桥接模式可以使它们在抽象层建立一个关联关系。
  2. 对于那些不希望使用继承或因为多层次继承导致系统类的个数急剧增加的系统,桥接模式尤为适用。
  3. 一个类存在两个独立变化的维度,且这两个维度都需要进行扩展。

注意事项

对于多个独立变化的维度,使用桥接模式再适合不过了。

示例

一套服装由衬衣、裤子、鞋子组成,衬衣分黑白,裤子分长短、鞋子分大小,一共有 2x2x2=8 种组合,如果使用普通继承可能导致类似下面的类爆炸,形成大量重复代码
image.png
现在使用桥接模式将三个维度独立,然后将三个维度通过组合创建一套服装
image.png

  1. #include "pch.h"
  2. #include <iostream>
  3. class IShirt
  4. {
  5. public:
  6. virtual int GetPrice() = 0;
  7. virtual std::string Info() = 0;
  8. };
  9. class BlackShirt : public IShirt
  10. {
  11. public:
  12. virtual int GetPrice()
  13. {
  14. return 20;
  15. }
  16. virtual std::string Info()
  17. {
  18. return std::string("Black Shirt");
  19. }
  20. };
  21. class WhiteShirt : public IShirt
  22. {
  23. public:
  24. virtual int GetPrice()
  25. {
  26. return 25;
  27. }
  28. virtual std::string Info()
  29. {
  30. return std::string("White Shirt");
  31. }
  32. };
  33. class IPants
  34. {
  35. public:
  36. virtual int GetPrice() = 0;
  37. virtual std::string Info() = 0;
  38. };
  39. class LongPants : public IPants
  40. {
  41. public:
  42. virtual int GetPrice()
  43. {
  44. return 45;
  45. }
  46. virtual std::string Info()
  47. {
  48. return std::string("Long Pants");
  49. }
  50. };
  51. class ShortPants : public IPants
  52. {
  53. public:
  54. virtual int GetPrice()
  55. {
  56. return 40;
  57. }
  58. virtual std::string Info()
  59. {
  60. return std::string("Short Pants");
  61. }
  62. };
  63. class IShoes
  64. {
  65. public:
  66. virtual int GetPrice() = 0;
  67. virtual std::string Info() = 0;
  68. };
  69. class BigShoes : public IShoes
  70. {
  71. public:
  72. virtual int GetPrice()
  73. {
  74. return 35;
  75. }
  76. virtual std::string Info()
  77. {
  78. return std::string("Big Shoes");
  79. }
  80. };
  81. class SmallShoes : public IShoes
  82. {
  83. public:
  84. virtual int GetPrice()
  85. {
  86. return 30;
  87. }
  88. virtual std::string Info()
  89. {
  90. return std::string("Small Shoes");
  91. }
  92. };
  93. class Suit
  94. {
  95. public:
  96. Suit(IShirt* const pShirt, IPants* const pPants, IShoes* const pShoes)
  97. {
  98. this->pShirt = pShirt;
  99. this->pPants = pPants;
  100. this->pShoes = pShoes;
  101. }
  102. ~Suit()
  103. {
  104. delete pShirt;
  105. pShirt = nullptr;
  106. delete pPants;
  107. pPants = nullptr;
  108. delete pShoes;
  109. pShoes = nullptr;
  110. }
  111. void Info()
  112. {
  113. std::cout << "Suit: " << pShirt->Info().c_str()
  114. << " + " << pPants ->Info().c_str()
  115. << " + " << pShoes ->Info().c_str() << std::endl;
  116. std::cout << "Price: " << pShirt->GetPrice() + pPants->GetPrice() + pShoes->GetPrice() << std::endl;
  117. }
  118. private:
  119. IShirt* pShirt;
  120. IPants* pPants;
  121. IShoes* pShoes;
  122. };
  123. // 调用示例
  124. int main()
  125. {
  126. Suit* SuitA = new Suit(new BlackShirt(), new LongPants(), new BigShoes());
  127. SuitA->Info();
  128. Suit* SuitB = new Suit(new WhiteShirt(), new ShortPants(), new BigShoes());
  129. SuitB->Info();
  130. Suit* SuitC = new Suit(new BlackShirt(), new LongPants(), new SmallShoes());
  131. SuitC->Info();
  132. }
>>>
Suit: Black Shirt + Long Pants + Big Shoes
Price: 100
Suit: White Shirt + Short Pants + Big Shoes
Price: 100
Suit: Black Shirt + Long Pants + Small Shoes
Price: 95