简介
场景
- 现实场景:国内电压是 220v,外国部分国家是 110v,如果去出差,会需要携带两个电源适配器,以应对这两种不同的电压。
- 数据库场景:每种编程语言都需要支持多种数据库,通常会抽象一层数据库连接层,例如 Java 的 JDBC,PHP 的 PDO。数据库连接层对应用开发人员提供标准接口,屏蔽了数据库底层的差异。数据库提供的接口则是千差万别的。所以,数据库连接层又拆分为两层,一层对外提供服务,一层用于连接不同的数据库。
- 具体代码场景:想使用一个已经完成的类,但是它的接口不符合需求。
假设已经有可以提供服务的目标类,客户类访问目标类时,发现其提供的接口不满足需求。此时在客户类和目标类中间加一层抽象,使不能直接交互的类可以一起工作。
定义一个包装类,包装不兼容接口的对象,这个包装类指的就是适配器(Adapter),它所包装的对象就是适配者(Adaptee),即被适配的类。
模式定义
将一个接口转换成客户希望的另一个接口,使接口不兼容的那些类可以一起工作。
模式特点
适配器模式包含四个角色:
Target:目标抽象类,定义接口标准,客户端可以直接调用
Adapter:适配器类,适配 Adaptee 与 Target,使其可以协同工作
Adaptee:适配者类,需要进行适配的接口
Client:客户类
适配器模式包括两种:
- 类结构型适配器:继承关系,Adapter 同时继承 Target 和 Adaptee 类。
- 对象结构型适配器:关联关系,Adapter 继承 Target,关联 Adaptee。
优点
- 符合“开闭原则”,可以用配置文件方便地更换适配器
- 解耦,通过引入一个适配器类来重用现有的适配者类
类适配器模式优点:
- Adapter 是 Adaptee 的子类,因此可以在 Adapter 中置换一些 Adaptee 的方法,使得适配器的灵活性更强。
对象适配器模式优点:
- 允许一个 Adapter 与多个 Adaptee 同时工作
缺点
类适配器模式的缺点:
- 对于不支持多继承的语言,一次最多只能适配一个 Adaptee,其使用有一定的局限性,不能将 Adaptee 和它的子类都适配到目标接口。当我们想要匹配一个类以及所有它的子类时,类 Adapter 不能胜任工作。
对象适配器模式的缺点:
- 重定义 Adaptee 的行为比较困难。
PHP 代码示例
类适配器模式
<?php
interface Target {
public function query();
}
class Adapter extends Adaptee implements Target {
public function del() {
echo "can not delete<br/>";
}
}
class Adaptee {
public function query() {
echo "Adaptee query<br/>";
}
}
class Client {
public function test() {
$adapter = new Adapter();
$adapter->query();
$adapter->del();
}
}
$c = new Client();
$c->test();
输出:
Adaptee query
can not delete
对象适配器模式
<?php
interface Target {
public function query();
}
class Adapter implements Target {
private $adaptee;
public function __construct(Adaptee $adaptee) {
$this->adaptee = $adaptee;
}
public function query() {
echo $this->adaptee->query();
}
public function del() {
echo "can not delete<br/>";
}
}
class Adaptee {
public function query() {
echo "Adaptee query<br/>";
}
}
class Client {
public function test() {
$adaptee = new Adaptee();
$adapter = new Adapter($adaptee);
$adapter->query();
$adapter->del();
}
}
$c = new Client();
$c->test();
输出:
Adaptee query
can not delete