代理模式(Proxy)的多种应用场景
代理模式是一种结构型设计模式,通过创建一个代理对象来控制对另一个对象的访问。它在JavaScript中有多种应用场景,从性能优化到安全控制,再到功能增强,都能发挥重要作用。
延迟初始化(虚拟代理)
虚拟代理常用于延迟昂贵对象的初始化,直到真正需要时才创建。这在资源密集型操作中特别有用。
class HeavyResource {
constructor() {
console.log('创建重量级资源...');
// 模拟耗时操作
this.data = Array(1000000).fill('data');
}
process() {
console.log('处理重量级资源');
}
}
class HeavyResourceProxy {
constructor() {
this.resource = null;
}
process() {
if (!this.resource) {
this.resource = new HeavyResource();
}
this.resource.process();
}
}
// 使用代理
const proxy = new HeavyResourceProxy();
// 此时尚未创建真实对象
proxy.process(); // 第一次调用时才会创建真实对象
访问控制(保护代理)
保护代理用于控制对敏感对象的访问,常用于权限验证场景。
class SensitiveData {
getData() {
return '敏感数据';
}
}
class DataAccessProxy {
constructor(user) {
this.user = user;
this.sensitiveData = new SensitiveData();
}
getData() {
if (this.user.role === 'admin') {
return this.sensitiveData.getData();
}
throw new Error('无权访问敏感数据');
}
}
// 使用示例
const admin = { role: 'admin' };
const user = { role: 'guest' };
const adminProxy = new DataAccessProxy(admin);
console.log(adminProxy.getData()); // 输出: 敏感数据
const userProxy = new DataAccessProxy(user);
try {
console.log(userProxy.getData()); // 抛出错误
} catch (e) {
console.error(e.message);
}
缓存代理
缓存代理可以存储昂贵操作的结果,避免重复计算。
class ExpensiveCalculation {
compute(input) {
console.log('执行昂贵计算...');
// 模拟耗时计算
return input * input;
}
}
class CachingProxy {
constructor() {
this.cache = new Map();
this.calculator = new ExpensiveCalculation();
}
compute(input) {
if (this.cache.has(input)) {
console.log('从缓存获取结果');
return this.cache.get(input);
}
const result = this.calculator.compute(input);
this.cache.set(input, result);
return result;
}
}
// 使用示例
const proxy = new CachingProxy();
console.log(proxy.compute(5)); // 执行计算
console.log(proxy.compute(5)); // 从缓存获取
远程代理
远程代理为远程对象提供本地代表,常用于API调用封装。
class RemoteAPI {
async fetchData(endpoint) {
console.log(`从${endpoint}获取数据...`);
const response = await fetch(endpoint);
return response.json();
}
}
class APIProxy {
constructor() {
this.cache = new Map();
this.api = new RemoteAPI();
}
async get(endpoint) {
if (this.cache.has(endpoint)) {
console.log('从缓存获取API数据');
return this.cache.get(endpoint);
}
const data = await this.api.fetchData(endpoint);
this.cache.set(endpoint, data);
return data;
}
}
// 使用示例
const apiProxy = new APIProxy();
apiProxy.get('https://api.example.com/data')
.then(data => console.log(data));
日志记录代理
日志代理可以在不修改原始对象的情况下添加日志功能。
class Database {
query(sql) {
// 实际数据库查询
return `查询结果: ${sql}`;
}
}
class LoggingProxy {
constructor(database) {
this.database = database;
}
query(sql) {
console.log(`[${new Date().toISOString()}] 执行查询: ${sql}`);
const result = this.database.query(sql);
console.log(`[${new Date().toISOString()}] 查询完成`);
return result;
}
}
// 使用示例
const db = new Database();
const loggedDb = new LoggingProxy(db);
console.log(loggedDb.query('SELECT * FROM users'));
验证代理
验证代理可以在方法调用前进行参数验证。
class UserService {
updateProfile(userId, data) {
// 实际更新逻辑
return `用户${userId}资料已更新`;
}
}
class ValidationProxy {
constructor(service) {
this.service = service;
}
updateProfile(userId, data) {
if (!userId) throw new Error('用户ID不能为空');
if (!data || typeof data !== 'object') {
throw new Error('资料必须是对象');
}
return this.service.updateProfile(userId, data);
}
}
// 使用示例
const service = new UserService();
const validatedService = new ValidationProxy(service);
try {
console.log(validatedService.updateProfile(123, { name: '张三' }));
validatedService.updateProfile(null, {}); // 抛出错误
} catch (e) {
console.error(e.message);
}
DOM事件代理
在前端开发中,事件代理是代理模式的典型应用。
class EventProxy {
constructor(element) {
this.element = element;
this.handlers = new Map();
}
addEventListener(type, handler) {
if (!this.handlers.has(type)) {
this.handlers.set(type, new Set());
this.element.addEventListener(type, (e) => {
this.handlers.get(type).forEach(h => h(e));
});
}
this.handlers.get(type).add(handler);
}
removeEventListener(type, handler) {
if (this.handlers.has(type)) {
this.handlers.get(type).delete(handler);
}
}
}
// 使用示例
const button = document.querySelector('button');
const proxy = new EventProxy(button);
const handler1 = () => console.log('Handler 1');
const handler2 = () => console.log('Handler 2');
proxy.addEventListener('click', handler1);
proxy.addEventListener('click', handler2);
// 点击按钮会触发两个处理器
// 移除一个处理器
proxy.removeEventListener('click', handler1);
图片懒加载代理
图片懒加载是前端性能优化的常见技术,可以使用代理模式实现。
class LazyImage {
constructor(placeholderSrc, realSrc) {
this.placeholder = placeholderSrc;
this.realSrc = realSrc;
this.image = new Image();
this.loaded = false;
}
load() {
if (!this.loaded) {
this.image.src = this.realSrc;
this.loaded = true;
}
}
render(element) {
const img = document.createElement('img');
img.src = this.placeholder;
img.dataset.realSrc = this.realSrc;
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
this.load();
img.src = this.realSrc;
observer.unobserve(img);
}
});
});
observer.observe(img);
element.appendChild(img);
}
}
// 使用示例
const container = document.getElementById('image-container');
const lazyImage = new LazyImage('placeholder.jpg', 'large-image.jpg');
lazyImage.render(container);
函数节流/防抖代理
代理模式可以用于实现函数的节流和防抖控制。
function debounce(fn, delay) {
let timer = null;
return function(...args) {
clearTimeout(timer);
timer = setTimeout(() => {
fn.apply(this, args);
}, delay);
};
}
function throttle(fn, interval) {
let lastTime = 0;
return function(...args) {
const now = Date.now();
if (now - lastTime >= interval) {
fn.apply(this, args);
lastTime = now;
}
};
}
// 原始函数
function handleScroll() {
console.log('处理滚动事件');
}
// 创建防抖代理
const debouncedScroll = debounce(handleScroll, 200);
// 创建节流代理
const throttledScroll = throttle(handleScroll, 200);
// 使用示例
window.addEventListener('scroll', debouncedScroll);
// 或
window.addEventListener('scroll', throttledScroll);
数据格式转换代理
代理可以在数据传递过程中进行格式转换。
class JSONAPI {
getData() {
return '{"name":"张三","age":30}';
}
}
class JSONToObjectProxy {
constructor(api) {
this.api = api;
}
getData() {
const json = this.api.getData();
return JSON.parse(json);
}
}
// 使用示例
const api = new JSONAPI();
const proxy = new JSONToObjectProxy(api);
console.log(proxy.getData()); // 输出JavaScript对象
多语言代理
代理模式可以用于实现多语言支持。
class Translator {
constructor(language) {
this.language = language;
this.translations = {
en: { hello: 'Hello', goodbye: 'Goodbye' },
zh: { hello: '你好', goodbye: '再见' },
fr: { hello: 'Bonjour', goodbye: 'Au revoir' }
};
}
translate(key) {
return this.translations[this.language][key] || key;
}
}
class TranslationProxy {
constructor(defaultLanguage = 'en') {
this.translator = new Translator(defaultLanguage);
}
setLanguage(language) {
this.translator.language = language;
}
t(key) {
return this.translator.translate(key);
}
}
// 使用示例
const i18n = new TranslationProxy('zh');
console.log(i18n.t('hello')); // 输出: 你好
i18n.setLanguage('fr');
console.log(i18n.t('hello')); // 输出: Bonjour
状态管理代理
在前端状态管理中,代理模式可以帮助实现状态的受控访问。
class Store {
constructor() {
this.state = { count: 0 };
this.subscribers = [];
}
getState() {
return this.state;
}
dispatch(action) {
switch (action.type) {
case 'INCREMENT':
this.state.count += 1;
break;
case 'DECREMENT':
this.state.count -= 1;
break;
}
this.notify();
}
subscribe(callback) {
this.subscribers.push(callback);
}
notify() {
this.subscribers.forEach(cb => cb(this.state));
}
}
class StoreProxy {
constructor() {
this.store = new Store();
}
getState() {
return { ...this.store.getState() }; // 返回副本防止直接修改
}
dispatch(action) {
console.log('派发动作:', action);
const result = this.store.dispatch(action);
console.log('新状态:', this.getState());
return result;
}
subscribe(callback) {
return this.store.subscribe(callback);
}
}
// 使用示例
const store = new StoreProxy();
store.subscribe(state => console.log('状态更新:', state));
store.dispatch({ type: 'INCREMENT' });
store.dispatch({ type: 'INCREMENT' });
store.dispatch({ type: 'DECREMENT' });
本站部分内容来自互联网,一切版权均归源网站或源作者所有。
如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn