本博客大部分内容来于免费在线学习设计模式

1:桥接模式

桥接模式是一种结构型设计模式, 可将一个大类或一系列紧密相关的类拆分为抽象和实现两个独立的层次结构, 从而能在开发时分别使用。

2:桥接模式问题

在现实生活中,某些类具有两个或多个维度的变化,如图形既可按形状分,又可按颜色分。如何设计类似于 Photoshop 这样的软件,能画不同形状和不同颜色的图形呢?如果用继承方式,m 种形状和 n 种颜色的图形就有 m×n 种,不但对应的子类很多,而且扩展困难。

20200830100724

3:桥接模式解决方案

问题的根本原因是我们试图在两个独立的维度——形状与颜色——上扩展形状类。这在处理类继承时是很常见的问题。

桥接模式通过将继承改为组合的方式来解决这个问题。具体来说,就是抽取其中一个维度并使之成为独立的类层次, 这样就可以在初始类中引用这个新层次的对象, 从而使得一个类不必拥有所有的状态和行为。

20200830101028

将颜色相关的代码抽取到拥有红色和蓝色两个子类的颜色类中,然后在形状类中添加一个指向某一颜色对象的引用成员变量。现在,形状类可以将所有与颜色相关的工作委派给连入的颜色对象。 这样的引用就成为了形状和颜色之间的桥梁。 此后,新增颜色将不再需要修改形状的类层次,反之亦然。

4:桥接模式结构

20200830101235

  1. 抽象部分 (Abstraction) 提供高层控制逻辑, 依赖于完成底层实际工作的实现对象。
  2. 实现部分 (Implementation) 为所有具体实现声明通用接口。 抽象部分仅能通过在这里声明的方法与实现对象交互。
    抽象部分可以列出和实现部分一样的方法, 但是抽象部分通常声明一些复杂行为, 这些行为依赖于多种由实现部分声明的原语操作
  3. 具体实现 (Concrete Implementations) 中包括特定于平台的代码。
  4. 精确抽象 (Refined Abstraction) 提供控制逻辑的变体。 与其父类一样, 它们通过通用实现接口与不同的实现进行交互。
  5. 通常情况下, 客户端 (Client) 仅关心如何与抽象部分合作。 但是, 客户端需要将抽象对象与一个实现对象连接起来。

代码示例:

实现形状和颜色的自由组合

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
public class BridgeTest {

public static void main(String[] args) {
// 红蓝
Color red = new Red();
Color blue = new Blue();

// 圆方
Shape round = new Round();
Shape square = new Square();

// 红色圆形
round.setColor(red);
System.out.println(round.getShape());
// 蓝色圆形
round.setColor(blue);
System.out.println(round.getShape());

// 红色方形
square.setColor(red);
System.out.println(square.getShape());
// 蓝色方形
square.setColor(blue);
System.out.println(square.getShape());
}
}

// 实现部分:颜色
interface Color {
String getColor();
}

// 具体实现:红色
class Red implements Color {

@Override
public String getColor() {
return "红色";
}
}

// 具体实现:蓝色
class Blue implements Color {

@Override
public String getColor() {
return "蓝色";
}
}

// 抽象部分:形状
abstract class Shape {
protected Color color;

public void setColor(Color color) {
this.color = color;
}

public abstract String getShape();
}

// 精确抽象:圆形
class Round extends Shape {

@Override
public String getShape() {
return color.getColor() + "圆形";
}
}

// 精确抽象:方形
class Square extends Shape {

@Override
public String getShape() {
return color.getColor() + "方形";
}
}

5:桥接模式适用场景

  1. 如果你想要拆分或重组一个具有多重功能的庞杂类 (例如能与多个数据库服务器进行交互的类), 可以使用桥接模式。
  2. 如果你希望在几个独立维度上扩展一个类,可使用该模式。
  3. 如果你需要在运行时切换不同实现方法,可使用桥接模式。

6:桥接模式优缺点

优点 缺点
你可以创建与平台无关的类和程序。 对高内聚的类使用该模式可能会让代码更加复杂。
客户端代码仅与高层抽象部分进行互动, 不会接触到平台的详细信息。
开闭原则。 你可以新增抽象部分和实现部分, 且它们之间不会相互影响。

7:桥接模式与其他模式关系

  1. 桥接模式通常会于开发前期进行设计,使你能够将程序的各个部分独立开来以便开发。另一方面,适配器模式通常在已有程序中使用, 让相互不兼容的类能很好地合作。
  2. 桥接、状态模式和策略模式(在某种程度上包括适配器)模式的接口非常相似。实际上,它们都基于组合模式——即将工作委派给其他对象,不过也各自解决了不同的问题。模式并不只是以特定方式组织代码的配方,你还可以使用它们来和其他开发者讨论模式所解决的问题。
  3. 你可以将抽象工厂模式和桥接搭配使用。如果由桥接定义的抽象只能与特定实现合作,这一模式搭配就非常有用。在这种情况下,抽象工厂可以对这些关系进行封装, 并且对客户端代码隐藏其复杂性。
  4. 你可以结合使用生成器模式和桥接模式:主管类负责抽象工作,各种不同的生成器负责实现工作。

8:桥接模式举例

比如一个人可以有多种属性,它可以是富人、穷人,也可以是老人、年轻人等等。桥接模式相当于将这些属性抽取出来,首先你是一个人,然后才有各种属性。

9:参考