阿里云主机折上折
  • 微信号
您当前的位置:网站首页 > 代理模式(Proxy)的多种应用场景

代理模式(Proxy)的多种应用场景

作者:陈川 阅读数:13244人阅读 分类: JavaScript

代理模式是一种结构型设计模式,通过创建一个代理对象来控制对另一个对象的访问。它在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

前端川

前端川,陈川的代码茶馆🍵,专治各种不服的Bug退散符💻,日常贩卖秃头警告级的开发心得🛠️,附赠一行代码笑十年的摸鱼宝典🐟,偶尔掉落咖啡杯里泡开的像素级浪漫☕。‌