代理模式:婚介所
用婚介所的例子理解和实现代理模式
问题
用”婚介所”的场景实现代理模式。
解答
代理模式:为对象提供一个代理,控制对该对象的访问。婚介所就是典型的代理——你不直接接触相亲对象,而是通过婚介所来筛选和沟通。
基础实现
// 定义接口:找对象的行为
class Person {
constructor(name, age, gender) {
this.name = name;
this.age = age;
this.gender = gender;
}
// 自我介绍
introduce() {
return `我是${this.name},${this.age}岁,${this.gender}`;
}
// 表达好感
sayLove(target) {
console.log(`${this.name} 对 ${target.name} 说:我喜欢你`);
}
}
// 婚介所(代理)
class MarriageAgency {
constructor(client) {
this.client = client; // 委托人
this.candidates = []; // 候选人列表
}
// 添加候选人
addCandidate(person) {
this.candidates.push(person);
}
// 代理筛选:根据条件过滤
filter(conditions) {
return this.candidates.filter(person => {
if (conditions.minAge && person.age < conditions.minAge) return false;
if (conditions.maxAge && person.age > conditions.maxAge) return false;
if (conditions.gender && person.gender !== conditions.gender) return false;
return true;
});
}
// 代理传话:先检查再转达
sayLoveProxy(target) {
// 代理可以做额外的事情:检查、记录、控制访问
if (target.gender === this.client.gender) {
console.log('婚介所:性别不匹配,无法传达');
return;
}
console.log(`婚介所:正在为 ${this.client.name} 传达心意...`);
this.client.sayLove(target);
}
}
// 使用
const zhangsan = new Person('张三', 28, '男');
const xiaohong = new Person('小红', 25, '女');
const xiaoming = new Person('小明', 30, '男');
// 张三委托婚介所
const agency = new MarriageAgency(zhangsan);
agency.addCandidate(xiaohong);
agency.addCandidate(xiaoming);
// 通过婚介所筛选
const matches = agency.filter({ gender: '女', minAge: 20, maxAge: 30 });
console.log('符合条件的候选人:', matches.map(p => p.name));
// 输出:符合条件的候选人:['小红']
// 通过婚介所传达心意
agency.sayLoveProxy(xiaohong);
// 输出:婚介所:正在为 张三 传达心意...
// 输出:张三 对 小红 说:我喜欢你
agency.sayLoveProxy(xiaoming);
// 输出:婚介所:性别不匹配,无法传达
ES6 Proxy 实现
// 使用 ES6 Proxy 实现更通用的代理
const person = {
name: '张三',
age: 28,
salary: 20000, // 敏感信息
phone: '13800138000' // 私密信息
};
// 婚介所代理:控制信息访问
const marriageProxy = new Proxy(person, {
get(target, prop) {
// 隐藏敏感信息
if (prop === 'salary') {
return '保密';
}
if (prop === 'phone') {
return '请通过婚介所联系';
}
return target[prop];
},
set(target, prop, value) {
// 验证修改
if (prop === 'age' && value < 0) {
throw new Error('年龄不能为负数');
}
target[prop] = value;
return true;
}
});
console.log(marriageProxy.name); // 张三
console.log(marriageProxy.salary); // 保密
console.log(marriageProxy.phone); // 请通过婚介所联系
虚拟代理:延迟加载照片
// 真实的照片对象(加载耗时)
class RealPhoto {
constructor(url) {
this.url = url;
this.loadPhoto(); // 模拟耗时加载
}
loadPhoto() {
console.log(`正在加载照片:${this.url}`);
}
display() {
console.log(`显示照片:${this.url}`);
}
}
// 照片代理:延迟加载
class PhotoProxy {
constructor(url) {
this.url = url;
this.realPhoto = null;
}
display() {
// 只有真正需要显示时才加载
if (!this.realPhoto) {
this.realPhoto = new RealPhoto(this.url);
}
this.realPhoto.display();
}
}
// 婚介所展示候选人照片
const photos = [
new PhotoProxy('photo1.jpg'),
new PhotoProxy('photo2.jpg'),
new PhotoProxy('photo3.jpg')
];
// 照片不会立即加载
console.log('照片列表已准备好');
// 只有查看时才加载
photos[0].display();
// 输出:正在加载照片:photo1.jpg
// 输出:显示照片:photo1.jpg
关键点
- 代理模式:为对象提供替身,控制对原对象的访问
- 婚介所职责:筛选过滤、信息保护、传话转达
- ES6 Proxy:通过
get/set拦截器实现属性访问控制 - 虚拟代理:延迟创建开销大的对象,按需加载
- 应用场景:权限控制、缓存、延迟加载、日志记录
目录