文章目录
面向对象设计模式之代理模式详解
在现代软件开发的浩瀚领域中,面向对象思想如同基石一般,支撑起了无数复杂而精妙的软件系统。而在面向对象开发的实践过程中,人们总结出了 23 种经典的设计模式,其中代理模式凭借其独特的设计理念和广泛的应用场景,成为了开发者们不可或缺的工具。
面向对象思想:现代软件开发的基石
现代软件开始的思想便是面向对象思想,它以一种更加贴近人类思维的方式来构建软件世界。在面向对象的编程范式中,“对象” 是核心概念。对象可以理解为对现实世界中事物的抽象,每个对象都具有属性和方法。属性用于描述对象的特征,而方法则用于定义对象能够执行的操作。
对象字面量是 JavaScript 中创建对象的一种简洁方式,它不需要使用new关键字和class定义,仅仅通过{}的形式就能创建对象。例如:
const person = {name: "Alice", age: 25, sayHello: function() { console.log("Hello!"); }};
在这个例子中,name和age是属性,sayHello是方法。对象字面量的表现力极强,通过key:value的形式,能够快速地定义出具有丰富属性和行为的对象。
随着面向对象编程的发展,逐渐从单纯的面向对象编程成长为面向接口编程。接口在其中起到了至关重要的作用,它定义了一组方法签名,而不关心具体的实现细节。不同的类只要实现了相同的接口,就可以在程序中进行互换,这大大提高了软件的可扩展性和可维护性。
代理模式:巧妙的中间层设计
设计模式是开发者在长期实践中总结出来的通用解决方案,对于有 1 - 2 年经验的程序员来说,熟练掌握设计模式是提升自身技术水平的关键,也是进入大厂实习面试的重要考察内容,更是未来成长为架构师的必经之路。而代理模式,作为 23 种设计模式中的一员,有着独特的魅力。
我们可以通过一个形象的例子来理解代理模式。假设 “我(me)” 想要给心仪的人 “莎(sha)” 送花,但是直接送花可能会因为各种原因失败。这时,“小红” 作为代理对象出现了。“小红” 和 “莎” 具有一样的方法receiveFlower,“我” 可以先把花送给 “小红”,再由 “小红” 转送给 “莎”。在这个过程中,“小红” 就像是一个中间代理,代替 “我” 完成送花的操作。
从技术层面来讲,代理模式通过实现相同的接口,使得代理对象和目标对象能够进行互换,从而更好地达到目的。代理对象在客户端和目标对象之间起到中介作用,它可以在调用目标对象的方法前后,执行一些额外的操作,比如权限验证、日志记录、性能监控等。
代理模式主要有以下几种类型:
- 静态代理:在编译期就确定了代理类和目标类,代理类和目标类实现相同的接口,代理类中持有目标类的引用,通过调用目标类的方法来实现具体功能。
- 动态代理:在运行时动态生成代理类,相比于静态代理,它更加灵活,不需要为每个目标类都创建一个代理类。
JavaScript 语法点与代理模式的结合
JavaScript 作为一门广泛应用于前端开发的编程语言,其丰富的语法特性为实现代理模式提供了便利。
基本语法点:
const常量:使用const声明的变量一旦被赋值,就不能再重新赋值。例如:const PI = 3.14159;,PI的值将始终保持不变,这在定义一些固定的常量时非常有用。
===恒等:===用于比较两个值是否严格相等,不仅比较值,还会比较数据类型。例如1 === "1"的结果为false,因为一个是数字类型,一个是字符串类型。
数据类型:JavaScript 的数据类型包括string(字符串)、number(数字,不分int和float)、boolean(布尔值)以及object(对象,其中array数组、function函数都属于对象类型)。了解这些数据类型对于正确处理数据和编写逻辑代码至关重要。
定时器的应用
setTimeout用于在指定的毫秒数后执行一次函数,其语法为setTimeout(function(){}, 1000),表示 1000 毫秒(即 1 秒)后执行传入的函数。例如,在代理对象中,可能需要在延迟一段时间后再调用目标对象的方法,这时就可以使用setTimeout。
JavaScript 实现代理模式示例
下面通过一个简单的 JavaScript 示例来展示代理模式的实现:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
</body>
<script>
const me = {
name: 'me',
age: 26,
location: {
city: 'Philadelphia',
temp: 92
},
isAdmin: false,
sendFlower(target) {
target.receiveFlower(me)
}
}
const sha = {
name: 'sha',
age: 18,
xq: 50,
receiveFlower(sender) {
if(sha.xq < 80) {
console.log('送花失败')
}else {
console.log('送花成功')
}
}
}
const xh = {
name: 'xiaohua',
age:18,
receiveFlower(sender) {
// if(sender.name === 'me') {
// console.log(sender.name + "我们在一起吧!")
// return
// }
// sha.receiveFlower(sender)
setTimeout(function() {
sha.xq = 99,
sha.receiveFlower(sender)
},2000)
}
}
</script>
</html>
// 定义接口
const FlowerReceiver = {
receiveFlower: function() {}
};
// 目标对象
const sha = {
receiveFlower: function() {
console.log("莎收到了花");
}
};
// 代理对象
const xiaoHong = {
receiveFlower: function() {
console.log("小红先接收花");
// 延迟1秒后调用莎的接收方法
setTimeout(() => {
sha.receiveFlower();
}, 1000);
}
};
// 使用代理对象
xiaoHong.receiveFlower();
在这个示例中,FlowerReceiver定义了一个接口,sha是目标对象,实现了receiveFlower方法。xiaoHong作为代理对象,也实现了receiveFlower方法,并且在调用目标对象的方法之前,先执行了一些额外的操作(打印日志和延迟调用)。
代理模式的应用场景
代理模式在实际开发中有着广泛的应用场景:
- 远程代理:当客户端需要访问远程服务器上的对象时,可以使用远程代理。代理对象负责处理网络通信,将客户端的请求发送到远程服务器,并将服务器的响应返回给客户端,这样客户端就不需要关心复杂的网络通信细节。
- 虚拟代理:对于一些创建开销较大的对象,可以使用虚拟代理。在对象实际被使用之前,代理对象并不创建真实的对象,而是在需要时才进行创建,从而提高系统的性能和资源利用率。
- 保护代理:保护代理用于控制对目标对象的访问权限。例如,在一个多用户系统中,不同用户对某些资源的访问权限不同,通过保护代理可以在调用目标对象的方法之前进行权限验证,确保只有具有相应权限的用户才能访问资源。
综上所述,代理模式作为面向对象设计模式中的重要一员,通过巧妙的中间层设计,为软件开发带来了更高的灵活性、可扩展性和可维护性。结合 JavaScript 的语法特性,我们能够更加便捷地实现代理模式,并将其应用到各种实际场景中。无论是对于初学者还是有经验的开发者,深入理解和掌握代理模式都将对提升编程能力和开发高质量软件起到重要的推动作用。