Adapter Pattern
适配器模式的实现与应用场景
问题
什么是适配器模式?在前端开发中如何应用?
解答
适配器模式将一个接口转换成另一个接口,使原本不兼容的类可以一起工作。
基础示例:统一不同地图 API
// 旧的地图服务
class OldMapService {
showLocation(lat, lng) {
console.log(`OldMap: 显示位置 (${lat}, ${lng})`);
}
}
// 新的地图服务,接口不同
class NewMapService {
display(coordinates) {
console.log(`NewMap: 显示位置 ${JSON.stringify(coordinates)}`);
}
}
// 适配器:让新服务兼容旧接口
class MapAdapter {
constructor(newMapService) {
this.map = newMapService;
}
// 适配旧接口
showLocation(lat, lng) {
const coordinates = { latitude: lat, longitude: lng };
this.map.display(coordinates);
}
}
// 使用
const oldMap = new OldMapService();
const newMap = new NewMapService();
const adaptedMap = new MapAdapter(newMap);
// 统一调用方式
oldMap.showLocation(39.9, 116.4); // OldMap: 显示位置 (39.9, 116.4)
adaptedMap.showLocation(39.9, 116.4); // NewMap: 显示位置 {"latitude":39.9,"longitude":116.4}
实际应用:统一 HTTP 请求库
// axios 风格的请求
class AxiosLikeHttp {
get(url, config) {
return fetch(url, { ...config, method: 'GET' }).then(res => res.json());
}
post(url, data, config) {
return fetch(url, {
...config,
method: 'POST',
body: JSON.stringify(data),
headers: { 'Content-Type': 'application/json' }
}).then(res => res.json());
}
}
// jQuery 风格的请求
class JQueryLikeHttp {
ajax(options) {
return fetch(options.url, {
method: options.type || 'GET',
body: options.data ? JSON.stringify(options.data) : undefined,
headers: options.data ? { 'Content-Type': 'application/json' } : {}
}).then(res => res.json());
}
}
// 适配器:将 jQuery 风格转为 axios 风格
class HttpAdapter {
constructor(jqueryHttp) {
this.http = jqueryHttp;
}
get(url, config) {
return this.http.ajax({ url, type: 'GET', ...config });
}
post(url, data, config) {
return this.http.ajax({ url, type: 'POST', data, ...config });
}
}
// 使用统一接口
const http = new HttpAdapter(new JQueryLikeHttp());
http.get('/api/users');
http.post('/api/users', { name: 'Tom' });
数据格式适配
// 后端返回的数据格式
const apiResponse = {
user_name: 'john_doe',
user_age: 25,
created_at: '2024-01-01'
};
// 前端期望的格式
// { userName: 'john_doe', userAge: 25, createdAt: '2024-01-01' }
// 数据适配器
function createDataAdapter(keyMap) {
return function adapt(data) {
const result = {};
for (const [oldKey, newKey] of Object.entries(keyMap)) {
if (data.hasOwnProperty(oldKey)) {
result[newKey] = data[oldKey];
}
}
return result;
};
}
// 使用
const userAdapter = createDataAdapter({
user_name: 'userName',
user_age: 'userAge',
created_at: 'createdAt'
});
const userData = userAdapter(apiResponse);
console.log(userData);
// { userName: 'john_doe', userAge: 25, createdAt: '2024-01-01' }
关键点
- 适配器不改变原有类,通过包装实现接口转换
- 常用于统一第三方库接口、兼容旧代码、数据格式转换
- 适配器与被适配对象是组合关系,不是继承
- 过度使用会增加系统复杂度,优先考虑重构
- 前端常见场景:API 封装、数据格式化、事件处理兼容
目录