设计模式之代理模式

代理模式详解:从送花场景到实际应用

什么是代理模式?

代理模式(Proxy Pattern)是一种结构型设计模式,它提供了一个代理对象来控制对另一个对象的访问。代理对象充当客户端和目标对象之间的中介,可以在访问目标对象前后执行额外的操作。

核心概念

代理模式包含三个主要角色:

  1. 目标对象(Real Subject):被代理的原始对象
  2. 代理对象(Proxy):控制对目标对象访问的代理
  3. 客户端(Client):使用代理对象的代码

送花场景中的代理模式

让我们通过一个生动的例子来理解代理模式:

场景描述

  • 小帅:想要送花的人(客户端)
  • 小美:收花的人(目标对象)
  • 小红:小美的朋友,作为代理(代理对象)

代码实现

javascript 复制代码
// 目标对象 - 小美
class XiaoMei {
    constructor() {
        this.name = '小美';
        this.xq = 60; // 心情值
    }
    
    receiveFlower(sender) {
        console.log(`小美收到了${sender.name}送的花`);
        
        if (this.xq > 80) {
            console.log('让我们在一起吧!');
            return 'accept';
        } else {
            console.log('抱歉,我们不合适。');
            return 'reject';
        }
    }
}

// 代理对象 - 小红
class XiaoHong {
    constructor(target) {
        this.name = '小红';
        this.target = target; // 被代理的对象
    }
    
    receiveFlower(sender) {
        console.log(`小红收到了${sender.name}送的花`);
        console.log('小红作为代理,正在处理...');
        
        // 代理可以修改目标对象的状态
        setTimeout(() => {
            console.log('小红偷偷提高了小美的心情值...');
            this.target.xq = 100;
            
            // 代理决定是否转发请求
            if (this.target.xq > 80) {
                console.log('小红决定转发给小美...');
                this.target.receiveFlower(sender);
            }
        }, 2000);
    }
}

// 客户端 - 小帅
class XiaoShuai {
    constructor() {
        this.name = '小帅';
    }
    
    sendFlower(target) {
        console.log(`${this.name}想要送花...`);
        target.receiveFlower(this);
    }
}

代理模式的优势

1. 控制访问

代理可以控制对目标对象的访问,决定是否转发请求。

2. 增强功能

代理可以在不修改目标对象的情况下,添加额外的功能。

3. 延迟加载

代理可以实现延迟加载,只在需要时才创建目标对象。

4. 缓存

代理可以缓存结果,避免重复计算。

代理模式的类型

1. 虚拟代理(Virtual Proxy)

延迟创建昂贵的对象。

javascript 复制代码
class ImageProxy {
    constructor(src) {
        this.src = src;
        this.image = null;
    }
    
    display() {
        if (!this.image) {
            this.image = new Image(this.src);
        }
        return this.image;
    }
}

2. 保护代理(Protection Proxy)

控制对敏感对象的访问。

javascript 复制代码
class BankAccountProxy {
    constructor(account, user) {
        this.account = account;
        this.user = user;
    }
    
    withdraw(amount) {
        if (this.user.hasPermission('withdraw')) {
            return this.account.withdraw(amount);
        } else {
            throw new Error('没有权限取款');
        }
    }
}

3. 远程代理(Remote Proxy)

为远程对象提供本地接口。

javascript 复制代码
class RemoteServiceProxy {
    constructor(url) {
        this.url = url;
    }
    
    async getData() {
        const response = await fetch(this.url);
        return response.json();
    }
}

4. 智能引用代理(Smart Reference Proxy)

在访问对象时执行额外操作。

javascript 复制代码
class SmartReferenceProxy {
    constructor(target) {
        this.target = target;
        this.accessCount = 0;
    }
    
    getData() {
        this.accessCount++;
        console.log(`访问次数: ${this.accessCount}`);
        return this.target.getData();
    }
}

实际应用场景

1. 网络请求代理

javascript 复制代码
class ApiProxy {
    constructor(api) {
        this.api = api;
        this.cache = new Map();
    }
    
    async get(url) {
        if (this.cache.has(url)) {
            console.log('从缓存返回数据');
            return this.cache.get(url);
        }
        
        const data = await this.api.get(url);
        this.cache.set(url, data);
        return data;
    }
}

2. 权限控制代理

javascript 复制代码
class PermissionProxy {
    constructor(service, user) {
        this.service = service;
        this.user = user;
    }
    
    delete(id) {
        if (this.user.role === 'admin') {
            return this.service.delete(id);
        } else {
            throw new Error('权限不足');
        }
    }
}

3. 日志记录代理

javascript 复制代码
class LoggingProxy {
    constructor(target) {
        this.target = target;
    }
    
    method1() {
        console.log('调用 method1');
        const result = this.target.method1();
        console.log('method1 执行完成');
        return result;
    }
}

代理模式 vs 装饰器模式

特性 代理模式 装饰器模式
目的 控制访问 增强功能
关系 一对一 一对多
生命周期 通常长期 可以动态添加/移除

最佳实践

1. 保持接口一致

代理对象应该与目标对象实现相同的接口。

2. 透明性

客户端应该能够像使用目标对象一样使用代理对象。

3. 职责单一

代理应该只负责控制访问,不应该包含业务逻辑。

4. 性能考虑

代理可能会影响性能,需要权衡利弊。

总结

代理模式是一种强大的设计模式,它通过提供代理对象来控制对目标对象的访问。在我们的送花场景中,小红作为代理,不仅控制了送花的过程,还能够在合适的时机修改小美的状态,最终影响送花的结果。

代理模式在实际开发中有广泛的应用,从网络请求缓存到权限控制,从延迟加载到日志记录,都能看到代理模式的身影。掌握代理模式,能够让我们写出更加灵活、可维护的代码。

相关推荐
Aerelin4 小时前
爬虫playwright入门讲解
前端·javascript·html·playwright
笙年4 小时前
JavaScript Promise,包括构造函数、对象方法和类方法
开发语言·javascript·ecmascript
桜吹雪4 小时前
LangChain.js/DeepAgents可观测性
javascript·人工智能
灵魂学者4 小时前
Vue3.x —— 父子通信
前端·javascript·vue.js·github
芳草萋萋鹦鹉洲哦6 小时前
【vue/js】文字超长悬停显示的几种方式
前端·javascript·vue.js
开发者小天6 小时前
React中的 闭包陷阱
前端·javascript·react.js
国服第二切图仔7 小时前
Electron for 鸿蒙pc项目实战之tab标签页组件
javascript·electron·harmonyos·鸿蒙pc
Neptune17 小时前
深入浅出:理解js的‘万物皆对象’与原型链
前端·javascript
阿迷不想上班7 小时前
windows自动任务定期执行
javascript
盗德8 小时前
最全音频处理WaveSurfer.js配置文档
前端·javascript