深入理解JavaScript系列(39):设计模式之适配器模式详解

作者:闭包旅人

时间:2026-10-29

浏览:74

本文详细解析JavaScript中的适配器模式,通过鸭子与火鸡的交互示例,展示如何将不兼容的接口转换为客户期望的接口。文章涵盖抽象类定义、具体构造函数实现及适配器类的创建,并对比了桥接、装饰者及代理模式的区别,帮助开发者理解何时使用适配器以解决接口不兼容问题。

文章目录

介绍

适配器模式概述

适配器模式(Adapter)的核心作用是将一个类或对象的接口转换为客户期望的另一个接口。该模式解决了因接口不兼容而无法协同工作的类或对象之间的通信问题,其本质可视为一种速成包装器(wrapper)。

正文

示例场景:鸭子与火鸡

为了直观理解,我们构建一个经典示例:鸭子(Duck)具备飞(fly)和嘎嘎叫(quack)的行为;而火鸡(Turkey)虽然也能飞,但叫声是咯咯叫(gobble)。若需让火鸡表现出嘎嘎叫的行为,我们可以复用鸭子的quack方法,但内部实际执行的是火鸡的gobble逻辑。为此,我们需要创建一个火鸡适配器,使火鸡能够支持quack方法调用。

代码实现步骤

接下来,我们将分步实现该模式。首先,定义鸭子和火鸡的抽象行为,即各自的基础方法函数:

代码如下:

//鸭子
var Duck = function(){
};
Duck.prototype.fly = function(){
throw new Error("该方法必须被重写!");
};
Duck.prototype.quack = function(){
throw new Error("该方法必须被重写!");
}
//火鸡
var Turkey = function(){
};
Turkey.prototype.fly = function(){
 throw new Error(" 该方法必须被重写 !");
};
Turkey.prototype.gobble = function(){
 throw new Error(" 该方法必须被重写 !");
};

随后,定义具体的鸭子和火鸡构造函数:


代码如下:

//鸭子
var MallardDuck = function () {
Duck.apply(this);
};
MallardDuck.prototype = new Duck(); //原型是Duck
MallardDuck.prototype.fly = function () {
console.log("可以飞翔很长的距离!");
};
MallardDuck.prototype.quack = function () {
console.log("嘎嘎!嘎嘎!");
};
//火鸡
var WildTurkey = function () {
 Turkey.apply(this);
};
WildTurkey.prototype = new Turkey(); //原型是Turkey
WildTurkey.prototype.fly = function () {
 console.log("飞翔的距离貌似有点短!");
};
WildTurkey.prototype.gobble = function () {
 console.log("咯咯!咯咯!");
};

适配器类构建

为了让火鸡支持quack方法,我们创建了一个新的适配器类TurkeyAdapter:


代码如下:

var TurkeyAdapter = function(oTurkey){
Duck.apply(this);
this.oTurkey = oTurkey;
};
TurkeyAdapter.prototype = new Duck();
TurkeyAdapter.prototype.quack = function(){
this.oTurkey.gobble();
};
TurkeyAdapter.prototype.fly = function(){
var nFly = 0;
var nLenFly = 5;
for(; nFly < nLenFly;){
this.oTurkey.fly();
nFly = nFly + 1;
    }
};

该构造函数接收一个火鸡实例对象,并通过Duck.apply(this)建立继承关系,其原型指向Duck。适配器重写了quack方法,内部调用oTurkey.gobble();同时修改了fly方法,使火鸡连续飞行5次(每次调用oTurkey.fly())。

测试与调用

调用过程清晰明了,通过测试即可验证结果:

代码如下:

var oMallardDuck = new MallardDuck();
var oWildTurkey = new WildTurkey();
var oTurkeyAdapter = new TurkeyAdapter(oWildTurkey);
//原有的鸭子行为
oMallardDuck.fly();
oMallardDuck.quack();
//原有的火鸡行为
oWildTurkey.fly();
oWildTurkey.gobble();
//适配器火鸡的行为(火鸡调用鸭子的方法名称)
oTurkeyAdapter.fly();
oTurkeyAdapter.quack();

总结

适用场景与模式对比

在以下场景中建议使用适配器模式:

1. 使用一个已存在的对象,但其方法或属性接口不符合当前需求; 2. 希望创建一个可复用的对象,使其能与不相关或接口不可见的对象协同工作; 3. 需使用已存在的对象,但不愿对每个对象进行原型继承以匹配其接口。对象适配器可适配其父对象的接口方法或属性。

此外,适配器模式易与其他模式混淆,此处简述主要区别:

1. 适配器与桥接模式看似相似,但桥接旨在将接口部分与实现部分分离,以便独立改变;而适配器旨在改变已有对象的接口。 2. 装饰者模式在不改变对象接口的前提下增强其功能,因此对程序透明性更好,支持递归组合;而纯适配器模式无法做到这一点。 3. 代理模式在不改变对象接口的前提下,为另一个对象定义了一个代理。

实用工具推荐

电子包浆

绿化、压缩、噪点和虚拟水印,自由调节做旧程度。

使用 ›
图片压缩

选择画质和输出格式,预览压缩前后的大小。

使用 ›
相关文章