故事
这是一个大佬讲给我听的,听得时候我也跟着哈哈大笑,听完之后又觉得"怀才不遇",不禁黯然神伤了起来,兄弟们且听我娓娓道来。
在 JavaScript 的世界里,设计模式如同魔法钥匙,能开启高效编程的大门。其中,代理模式更是有着独特的魅力,就像爱情故事中的神秘使者,为恋人们传递着心意。
故事的主人公是浪遏、小美和小红。浪遏深爱着小美,却不知如何表达自己的爱意。小红,作为小美的老乡,就像一个代理对象,在这个爱情故事中扮演着重要的角色。
小红和小美有着相同的 “接口”,都拥有接收鲜花的方法receiveFlower。浪遏想送花给小美,但又担心小美心情不好时被拒绝。于是,他决定先把花送给小红,让小红在合适的时候转送给小美。
在这个故事中,浪遏的目的是送花,但又担心小美心情不好时被拒绝,于是找到小红转送给小美,其实这个举动就是在走代理。
在 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>
<script>
// 面向对象 OO
// js 对象字面量 创建一个对象
const gan = {
name: "浪遏", // string
age: 17, // number 整数 + 浮点数
hometown: "吉安", //
hobbies: ['学习', '搞钱'], // js没有数组, 也是对象
isSingle: true, // boolean
// 形参
sendFlower(target) {
target.receiveFlower(gan);
}
}
// 申明了常量对象 对象字面量 从字面意义就可以了解对象
const xm = {
name: '小美',
age: 19,
hometown: '九江',
sex: 'female',
xq: 50,
receiveFlower(sender) {
if (xm.xq < 80) {
console.log('gun~~~')
} else {
console.log(sender.name + '送了花, 万达走一波')
}
}
}
// 用js
const xh = {
name: '小红',
hometown: '吉安',
// 收花的权利, 接口 interface
receiveFlower(sender) {
// 恒等
if (sender.name === '浪遏') {
console.log('让我们在一起吧,暗恋你很久了....')
}
// 代理送花意义很大
setTimeout(function () {
xm.xq = 99
xm.receiveFlower(sender)
}, 2000)
}
}
</script>
</body>
</html>
在这段代码中,我们可以发现,作为代理的小红,除了完成浪遏的委托之外还可以做一些额外的事情,从这里我们可以引出代理的特点:它在不改变原始对象的前提下,通过引入一个代理对象来控制对原始对象的访问,实现额外的功能。
故事引发的思考
那么代理模式在前端有什么应用呢?
一、数据请求代理
-
解决跨域问题:
- 当前端与后端部署在不同的域名下时,会受到浏览器同源策略的限制,导致无法直接进行数据交互。通过设置代理服务器,可以将请求转发到目标服务器,从而绕过同源策略的限制。
- 例如,使用 Node.js 创建一个中间层服务器,前端将请求发送到中间层服务器,中间层服务器再将请求转发到后端服务器,并将响应返回给前端。这样,前端就可以像访问同域资源一样获取数据。
-
缓存数据:
-
代理服务器可以缓存经常访问的数据,当再次请求相同的数据时,可以直接从缓存中返回,提高响应速度。
-
比如,对于一些不经常变化的数据,如商品列表、用户信息等,可以在代理服务器中设置缓存策略,减少对后端服务器的请求压力。
-
二、图片懒加载代理
-
提升页面加载速度:
- 当页面中有大量图片时,如果一次性全部加载,会导致页面加载速度变慢。使用代理可以实现图片懒加载,即当图片进入可视区域时才进行加载。
- 前端可以通过设置一个占位图,并在需要加载图片时,向代理发送请求。代理根据请求的图片地址进行加载,并将加载后的图片返回给前端进行展示。
-
节省带宽资源:
-
对于用户可能不会浏览到的图片,不进行加载,可以节省带宽资源。
-
例如,在一个长页面中,只有当用户滚动页面使图片进入可视区域时,才会触发图片的加载,避免了不必要的带宽浪费。
-
三、接口模拟代理
-
方便开发和调试:
- 在前端开发过程中,后端接口可能还未完成或者不稳定。通过使用代理来模拟后端接口,可以让前端开发人员在没有后端支持的情况下进行开发和调试。
- 可以使用工具如 Mock.js 来创建模拟数据,代理服务器根据前端的请求返回模拟数据,使得前端开发不受后端进度的影响。
-
快速验证功能:
-
对于一些复杂的业务逻辑,需要通过接口返回的数据来进行验证。使用接口模拟代理可以快速验证前端功能的正确性,提高开发效率。
-
例如,在开发一个电商网站时,可以模拟商品搜索接口、购物车接口等,以便在没有真实数据的情况下测试前端的功能。
-
四、安全代理
-
防止 XSS 攻击:
- 代理服务器可以对用户输入的数据进行过滤和转义,防止恶意脚本注入到页面中。
- 当用户提交表单数据或者在页面中输入内容时,代理服务器可以对数据进行检查,去除潜在的危险字符,保护前端应用的安全。
-
限制访问权限:
-
通过代理服务器可以对用户的访问进行控制,限制只有授权用户才能访问特定的页面或资源。
-
例如,对于一些需要登录才能访问的页面,可以在代理服务器中进行权限验证,只有通过验证的用户才能访问相应的页面。
-
代理在前端开发中发挥着重要的作用,能够解决跨域问题、提升页面加载速度、方便开发调试以及提高应用的安全性。通过合理地运用代理技术,可以提高前端开发的效率和质量,为用户提供更好的体验。
故事的真相
其实在这个故事中,忘了交代浪遏的身份,他就是自学两个月半的java大帅哥,要学习资料的兄弟可以看下去,看看他是如何学习的🤭
以下是学习资料
interface Document {
void displayContent();
}
class RealDocument implements Document {
private String content;
public RealDocument(String content) {
this.content = content;
}
@Override
public void displayContent() {
System.out.println("Displaying content: " + content);
}
}
class DocumentProxy implements Document {
private RealDocument realDocument;
private String content;
private static int accessCount = 0;
public DocumentProxy(String content) {
this.content = content;
}
@Override
public void displayContent() {
accessCount++;
if (realDocument == null) {
realDocument = new RealDocument(content);
}
realDocument.displayContent();
System.out.println("Document accessed " + accessCount + " times.");
}
}
// 客户端代码
public class Client {
public static void main(String[] args) {
Document document = new DocumentProxy("Hello, World!");
document.displayContent(); // 显示内容并记录访问次数
document.displayContent(); // 再次显示内容并记录访问次数
}
}
以下是浪遏做的笔记
这段代码实现了一个简单的代理模式示例。代理模式通过创建一个代理对象来控制对真实对象的访问,在这个例子中,DocumentProxy就是代理对象,RealDocument是真实对象,它们都实现了Document接口。
-
interface Document定义了一个文档的行为,即displayContent方法,用于显示文档的内容。 -
class RealDocument实现了Document接口,代表真实的文档对象。在构造函数中接收一个字符串内容,并在displayContent方法中打印出这个内容。 -
class DocumentProxy也实现了Document接口,作为真实文档对象的代理。它包含以下几个重要的部分:- 私有成员变量
RealDocument realDocument,用于存储真实文档对象的引用。初始时为null,在需要的时候才创建真实文档对象。 - 私有成员变量
String content,存储要显示的内容,与真实文档对象中的内容对应。 - 静态成员变量
int accessCount,用于记录文档被访问的次数。
- 私有成员变量
-
在
displayContent方法中:-
每次调用这个方法时,都会增加访问次数。
-
如果真实文档对象还未创建(即
realDocument == null),则创建一个新的RealDocument对象,并将存储的内容传递给它。 -
最后,如果真实文档对象已经存在,直接调用真实文档对象的
displayContent方法来显示内容,并打印出文档被访问的次数。
-
在客户端代码中,创建了一个代理对象DocumentProxy,并传入内容 “Hello, World!”。然后两次调用代理对象的displayContent方法。
第一次调用时,由于真实文档对象还未创建,代理对象会创建真实文档对象,显示内容并记录访问次数为 1。第二次调用时,真实文档对象已经存在,直接调用真实文档对象的方法显示内容,并记录访问次数为 2。
通过这种方式,代理对象DocumentProxy控制了对真实对象RealDocument的创建和访问,同时还能够记录文档的访问次数,实现了代理模式的典型应用场景。
在java中的应用很多,例如动态代理就是代理模式,SpringAOP就是动态 代理,RPC框架也是使用了动态代理才使得调用远程方法和本地方法一样。 所以,统一报错、监控、限流、鉴权等等,需要跟业务解耦的功能,基本上都是 使用代理类进行统一处理的。
感悟
代理模式真的很重要!!!🤡 单身了19年,这下稳啦!