初识设计模式——桥接模式(Bridge Pattern)

cuixiaogang

桥接模式(Bridge Pattern)是一种结构型设计模式,它将抽象部分与实现部分分离,使它们可以独立地变化。这种模式通过组合的方式,将一个对象的不同维度的变化分离开来,避免了过多的继承关系导致的类爆炸问题。

“桥接”解析

“桥接”即为: 通过一个 “桥梁” 将两个独立的维度连接起来,使其两端能够独立发展变化。这一比喻类似于现实中的桥梁,将两岸(抽象与实现)连接,同时允许两岸各自发展。

桥接模式的构成

  • 抽象化(Abstraction):定义抽象类的接口,持有一个对实现化对象的引用。
  • 扩展抽象化(Refined Abstraction):扩展抽象化角色,实现抽象化中的业务方法,并调用实现化角色中的业务方法。
  • 实现化(Implementor):定义实现化角色的接口,供扩展抽象化角色调用。
  • 具体实现化(Concrete Implementor):给出实现化角色接口的具体实现。

桥接模式结构图

案例

场景

在 WEB 开发中,我们可能会遇到需要支持多种数据库(如 MySQL、SQLite 等)的情况。使用桥接模式可以将数据库操作的抽象部分与具体的数据库实现分离,使得我们可以在不修改抽象部分的情况下,轻松地切换数据库。

代码

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
<?php
// 实现化接口:数据库操作接口
interface DatabaseInterface {
public function connect();
public function query($sql);
public function close();
}

// 具体实现化:MySQL数据库实现
class MySQLDatabase implements DatabaseInterface {
public function connect() {
echo "Connected to MySQL database.<br>";
}

public function query($sql) {
echo "Executing query: $sql on MySQL database.<br>";
}

public function close() {
echo "Closed MySQL database connection.<br>";
}
}

// 具体实现化:SQLite数据库实现
class SQLiteDatabase implements DatabaseInterface {
public function connect() {
echo "Connected to SQLite database.<br>";
}

public function query($sql) {
echo "Executing query: $sql on SQLite database.<br>";
}

public function close() {
echo "Closed SQLite database connection.<br>";
}
}

// 抽象化:数据库操作抽象类
abstract class DatabaseOperation {
protected $database;

public function __construct(DatabaseInterface $database) {
$this->database = $database;
}

public function executeQuery($sql) {
$this->database->connect();
$this->database->query($sql);
$this->database->close();
}
}

// 扩展抽象化:用户数据库操作类
class UserDatabaseOperation extends DatabaseOperation {
public function getUser($id) {
$sql = "SELECT * FROM users WHERE id = $id";
$this->executeQuery($sql);
}
}

// 使用示例
$mysqlDatabase = new MySQLDatabase();
$userMysqlOperation = new UserDatabaseOperation($mysqlDatabase);
$userMysqlOperation->getUser(1);

$sqliteDatabase = new SQLiteDatabase();
$userSqliteOperation = new UserDatabaseOperation($sqliteDatabase);
$userSqliteOperation->getUser(2);
?>

UML类图

UML类图

桥接模式的适用场景

  • 当你不希望在抽象和实现部分之间建立固定的绑定关系时,例如在运行时动态地选择具体的实现。
  • 当一个类存在多个变化维度,且这些维度需要独立变化时,使用桥接模式可以将这些维度分离,减少类的数量。
  • 当你需要在多个平台上使用不同的实现时,桥接模式可以帮助你将平台相关的实现与抽象部分分离。

桥接模式的优缺点

优点

  • 解耦抽象和实现:使抽象和实现可以独立地变化,提高了系统的可扩展性和可维护性。
  • 可扩展性强:可以方便地增加新的抽象或实现,而不会影响到其他部分。
  • 符合开闭原则:对扩展开放,对修改关闭。

缺点

  • 增加系统复杂度:由于使用了组合和接口,会增加系统的复杂度,理解和维护成本相对较高。
  • 不适用于简单场景:对于简单的系统,使用桥接模式可能会显得过于复杂。

后记

合成/聚合复用原则中提及了以下两种定义:

  • 聚合表示一种弱的‘拥有’关系,体现的是A对象可以包含B对象,但B对象不是A对象的一部分。
  • 合成则是一种强的‘拥有’关系,体现了严格的部分和整体的关系,部分和整体的生命周期一样。

在桥接模式里,抽象部分(Abstraction)会持有一个对实现部分(Implementor)的引用,这属于组合(聚合)关系。这种组合(聚合)关系让抽象部分可以在运行时动态地选择不同的实现,而非通过继承来固定实现。