设计模式之代理模式

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

什么是代理模式?

代理模式(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. 性能考虑

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

总结

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

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

相关推荐
llq_3503 小时前
为什么 JS 代码执行了,但页面没马上变?
前端·javascript
new出一个对象3 小时前
vue实现打印PDF文档
javascript·vue.js·pdf
aricvvang4 小时前
🚀 NestJS 使用 cache-manager-redis-store 缓存无效?真相在这里!
javascript·后端·nestjs
皮皮虾我们跑4 小时前
前端HTML常用基础标
前端·javascript·html
卓码软件测评4 小时前
第三方CMA软件测试机构:页面JavaScript动态渲染生成内容对网站SEO的影响
开发语言·前端·javascript·ecmascript
Mintopia4 小时前
📚 Next.js 分页 & 模糊搜索:在无限数据海里优雅地翻页
前端·javascript·全栈
Mintopia4 小时前
⚖️ AIGC版权确权技术:Web内容的AI生成标识与法律适配
前端·javascript·aigc
周家大小姐.4 小时前
vue实现模拟deepseekAI功能
前端·javascript·vue.js
鹏多多4 小时前
用useTransition解决React性能卡顿问题+实战例子
前端·javascript·react.js