一、前言

本篇主题为结构型模式中的第二个模式--桥接模式。上篇 Java 设计模式主题为《Java 设计模式之适配器模式(六)》

二、简单介绍

2.1 定义

桥接模式,是结构型的设计模式之一。桥接模式基于类的最小设计原则,通过使用封装,聚合以及继承等行为来让不同的类承担不同的责任。它的主要特点是把抽象(abstraction)与行为实现(implementation)分离开来,从而可以保持各部分的独立性以及应对它们的功能扩展。

2.2 应用场景

处理多层继承结构,多维度变化的场景。将各个维度设计成独立的继承结构,使得各个维度可以独立的扩展。

三、实现方式

我们以电脑为例,在网上商城中,我们可以看到电脑的分类菜单,分类结构如下图所示:

图中将电脑结构分成 3 级,第 1 级就是商品名称(电脑),第 2 级是电脑类型分类,第 3 级是品牌分类。现在,我们试着通过代码实现上图的结构:

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
public interface Computer {
void info();
}

class Desktop implements Computer {
@Override
public void info() {
System.out.println("台式电脑!");
}
}

class Laptop implements Computer {
@Override
public void info() {
System.out.println("笔记本电脑!");
}
}

class LenovoDesktop extends Desktop {
@Override
public void info() {
System.out.println("联想台式电脑");
}
}

class AsusDesktop extends Desktop {
@Override
public void info() {
System.out.println("华硕台式电脑");
}
}

class LenovoLaptop extends Laptop {
@Override
public void info() {
System.out.println("联想笔记本电脑");
}
}

class AsusLaptop extends Laptop {
@Override
public void info() {
System.out.println("华硕笔记本电脑");
}
}

上述代码通过继承方式实现了图中的电脑分类结构。但是,使用继承的方式存在几个问题:

  1. 扩展性问题:如果新增平板电脑分类,需要添加 N 个品牌子类。如果新增索尼品牌,其他电脑分类也需要添加相应子类。

  2. 违背单一职责原则:新增类型或新增品牌都会导致第 3 级目录结构的变化。

下面,我们使用桥接模式解决上述问题:

我们从 2 个维度分类,将它们分离独立出来,即将电脑类型和电脑品牌分离出来。

品牌维度:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public interface Brand {
void info();
}

class LenovoBrand implements Brand {

@Override
public void info() {
System.out.println("联想");
}

}

class AsusBrand implements Brand {

@Override
public void info() {
System.out.println("华硕");
}

}

类型维度:

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
public abstract class Computer {

protected Brand brand;

public Computer(Brand brand) {
this.brand = brand;
}

public void info() {
this.brand.info();
}
}

class Desktop extends Computer {

public Desktop(Brand brand) {
super(brand);
}

public void info() {
super.info();
System.out.println("台式电脑");
}

}

class Laptop extends Computer {

public Laptop(Brand brand) {
super(brand);
}

public void info() {
super.info();
System.out.println("笔记本电脑");
}

}

客户端:

1
2
3
4
5
6
7
8
9
public class Client {

public static void main(String[] args) {

Computer computer = new Desktop(new LenovoBrand());

computer.info();
}
}

结果打印:

1
2
联想
台式电脑

当我们在其中一个维度上的代码进行修改时并不是影响到另一个维度的代码,这样遵循了单一职责原则,同时代码结构也变得灵活起来。

UML 类图表示如下: