外观模式
用统一接口简化复杂子系统的调用
问题
什么是外观模式?如何在前端开发中应用?
解答
外观模式(Facade Pattern)为复杂的子系统提供一个简单的统一接口,隐藏内部复杂性。
基本示例
// 复杂的子系统
class CPU {
freeze() {
console.log('CPU 冻结');
}
jump(position) {
console.log(`CPU 跳转到 ${position}`);
}
execute() {
console.log('CPU 执行指令');
}
}
class Memory {
load(position, data) {
console.log(`内存加载数据到 ${position}`);
}
}
class HardDrive {
read(sector, size) {
console.log(`硬盘读取扇区 ${sector}`);
return 'boot data';
}
}
// 外观类 - 提供简单接口
class ComputerFacade {
constructor() {
this.cpu = new CPU();
this.memory = new Memory();
this.hardDrive = new HardDrive();
}
// 一键启动,隐藏复杂的启动流程
start() {
this.cpu.freeze();
this.memory.load(0, this.hardDrive.read(0, 1024));
this.cpu.jump(0);
this.cpu.execute();
console.log('电脑启动完成');
}
}
// 使用
const computer = new ComputerFacade();
computer.start(); // 一行代码完成复杂操作
前端实际应用:HTTP 请求封装
// 底层 API(复杂)
class XMLHttpRequestHandler {
send(method, url, data, headers) {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.open(method, url);
Object.keys(headers || {}).forEach(key => {
xhr.setRequestHeader(key, headers[key]);
});
xhr.onload = () => resolve(JSON.parse(xhr.responseText));
xhr.onerror = reject;
xhr.send(JSON.stringify(data));
});
}
}
class AuthManager {
getToken() {
return localStorage.getItem('token');
}
}
class ErrorHandler {
handle(error) {
console.error('请求错误:', error);
// 统一错误处理逻辑
}
}
// 外观类 - 简化 HTTP 请求
class HttpFacade {
constructor() {
this.xhr = new XMLHttpRequestHandler();
this.auth = new AuthManager();
this.errorHandler = new ErrorHandler();
}
// 统一的请求方法
async request(method, url, data = null) {
const headers = {
'Content-Type': 'application/json',
'Authorization': `Bearer ${this.auth.getToken()}`
};
try {
return await this.xhr.send(method, url, data, headers);
} catch (error) {
this.errorHandler.handle(error);
throw error;
}
}
// 简化的 API
get(url) {
return this.request('GET', url);
}
post(url, data) {
return this.request('POST', url, data);
}
put(url, data) {
return this.request('PUT', url, data);
}
delete(url) {
return this.request('DELETE', url);
}
}
// 使用 - 极其简单
const http = new HttpFacade();
http.get('/api/users');
http.post('/api/users', { name: 'John' });
浏览器兼容性处理
// 外观模式处理浏览器差异
const EventFacade = {
// 统一事件绑定
addEvent(element, type, handler) {
if (element.addEventListener) {
element.addEventListener(type, handler, false);
} else if (element.attachEvent) {
element.attachEvent('on' + type, handler);
} else {
element['on' + type] = handler;
}
},
// 统一事件移除
removeEvent(element, type, handler) {
if (element.removeEventListener) {
element.removeEventListener(type, handler, false);
} else if (element.detachEvent) {
element.detachEvent('on' + type, handler);
} else {
element['on' + type] = null;
}
},
// 统一获取事件对象
getEvent(event) {
return event || window.event;
},
// 统一阻止默认行为
preventDefault(event) {
if (event.preventDefault) {
event.preventDefault();
} else {
event.returnValue = false;
}
}
};
// 使用 - 无需关心浏览器差异
EventFacade.addEvent(document.getElementById('btn'), 'click', () => {
console.log('clicked');
});
关键点
- 简化接口:将复杂子系统的多个接口合并为一个简单接口
- 解耦:客户端与子系统解耦,子系统变化不影响调用方
- 不限制访问:外观模式不阻止直接访问子系统,只是提供便捷入口
- 常见场景:HTTP 请求封装、浏览器兼容处理、第三方库封装
- 与适配器区别:适配器转换接口,外观简化接口
目录