• 【前端设计模式】之代理模式


    代理模式特性

    代理模式是一种结构型设计模式,它通过创建一个代理对象来控制对另一个对象的访问。代理模式的主要特性包括:

    1. 代理对象与目标对象实现相同的接口或继承相同的基类,使得客户端可以透明地使用代理对象。
    2. 代理对象持有对目标对象的引用,并在必要时将客户端的请求转发给目标对象。
    3. 代理对象可以在转发请求之前或之后执行一些额外的操作,例如权限验证、缓存、日志记录等。

    前端应用示例

    请求代理

    当发起请求时,可以代理请求在转发请求之前执行一些额外的操作,或者在转发请求之后做一些额外的操作

     
    
    1. // 定义目标对象接口
    2. class Subject {
    3. request() {
    4. // 处理请求
    5. }
    6. }
    7. // 定义具体目标对象类
    8. class RealSubject extends Subject {
    9. request() {
    10. // 处理真实请求
    11. }
    12. }
    13. // 定义代理对象类
    14. class Proxy extends Subject {
    15. constructor() {
    16. super();
    17. this.realSubject = new RealSubject();
    18. }
    19. request() {
    20. // 在转发请求之前或之后执行一些额外操作
    21. this.preRequest();
    22. this.realSubject.request();
    23. this.postRequest();
    24. }
    25. preRequest() {
    26. // 在转发请求之前执行一些额外操作
    27. }
    28. postRequest() {
    29. // 在转发请求之后执行一些额外操作
    30. }
    31. }
    32. // 使用示例
    33. const proxy = new Proxy();
    34. proxy.request(); // 通过代理对象发送请求,并在转发前后执行额外操作

    图片懒加载

    当页面中存在大量图片时,为了提高页面加载速度和性能,可以使用图片懒加载技术。在这种情况下,可以使用代理模式,在图片未进入可视区域之前,使用占位图或者小图进行替换,在图片进入可视区域时再加载真实图片。

    1. // 定义目标对象
    2. class ImageLoader {
    3. constructor(imageElement) {
    4. this.imageElement = imageElement;
    5. this.realImage = new Image();
    6. this.realImage.onload = () => {
    7. this.imageElement.src = this.realImage.src;
    8. };
    9. }
    10. load() {
    11. // 模拟从服务器加载真实图片的操作
    12. console.log("Loading real image...");
    13. this.realImage.src = this.imageElement.dataset.src;
    14. }
    15. }
    16. // 定义图片懒加载代理对象
    17. class LazyImageProxy {
    18. constructor(imageElement) {
    19. this.imageElement = imageElement;
    20. }
    21. load() {
    22. if (this.imageElement.getBoundingClientRect().top < window.innerHeight) {
    23. const imageLoader = new ImageLoader(this.imageElement);
    24. imageLoader.load();
    25. }
    26. }
    27. }
    28. // 使用示例
    29. const lazyImages = document.querySelectorAll(".lazy-image");
    30. lazyImages.forEach((image) => {
    31. const lazyImageProxy = new LazyImageProxy(image);
    32. lazyImageProxy.load();
    33. });

    在上述示例中,我们定义了一个目标对象ImageLoader,它负责加载真实的图片。

    然后,我们定义了一个图片懒加载代理对象LazyImageProxy,它持有对目标对象的引用,并在load方法中实现了对图片懒加载的逻辑。当客户端调用load方法时,代理对象首先检查图片是否进入可视区域(通过判断其位置是否小于窗口高度),如果是则创建目标对象ImageLoader并调用其load方法加载真实图片。

    通过使用代理模式实现图片懒加载,可以减少页面加载时对大量图片的请求,提高页面加载速度和性能。同时,代理对象还可以隐藏目标对象的具体实现细节,保护目标对象的安全性。

    数据缓存代理

    为了减少网络请求和提高页面加载速度,可以使用代理模式在客户端或服务端缓存数据。当客户端请求数据时,代理对象首先检查缓存中是否存在数据,如果存在则直接返回缓存数据,否则再向目标对象请求数据并将其缓存起来。

     
    
    1. // 定义目标对象
    2. class DataService {
    3. fetchData(key) {
    4. // 模拟从服务器获取数据的操作
    5. console.log("Fetching data from server...");
    6. return `Data for ${key}`;
    7. }
    8. }
    9. // 定义数据缓存代理对象
    10. class DataCacheProxy {
    11. constructor() {
    12. this.cache = {};
    13. this.dataService = new DataService();
    14. }
    15. fetchData(key) {
    16. if (this.cache[key]) {
    17. console.log("Fetching data from cache...");
    18. return this.cache[key];
    19. } else {
    20. const data = this.dataService.fetchData(key);
    21. this.cache[key] = data;
    22. return data;
    23. }
    24. }
    25. }
    26. // 使用示例
    27. const proxy = new DataCacheProxy();
    28. console.log(proxy.fetchData("example")); // 从服务器获取数据,并缓存起来
    29. console.log(proxy.fetchData("example")); // 从缓存中获取数据

    在上述示例中,我们定义了一个目标对象DataService,它模拟了从服务器获取数据的操作。然后,我们定义了一个数据缓存代理对象DataCacheProxy,它持有对目标对象的引用,并在fetchData方法中实现了对数据的缓存逻辑。

    当客户端调用fetchData方法时,代理对象首先检查缓存中是否存在对应的数据,如果存在则直接返回缓存的数据;否则调用目标对象的fetchData方法从服务器获取数据,并将其缓存起来。

    通过使用代理模式实现数据缓存代理,可以减少对服务器的请求次数,提高数据访问的性能和效率。同时,代理对象还可以隐藏目标对象的具体实现细节,保护目标对象的安全性。

    ES6的Proxy

    ES6引入了Proxy对象,它是一种代理模式的实现,用于拦截并自定义对象的操作。Proxy对象可以拦截并重定义JavaScript对象的底层操作,例如属性访问、赋值、函数调用等。通过使用Proxy对象,我们可以在目标对象上添加额外的行为或修改默认行为。

    Proxy对象的基本语法如下:

    const proxy = new Proxy(target, handler);
    
    • target:要代理的目标对象。
    • handler:一个包含各种拦截操作的处理程序对象。

    下面是一些常见的Proxy拦截操作:

    1. get(target, property, receiver):拦截对目标对象属性的读取操作。
    2. set(target, property, value, receiver):拦截对目标对象属性的赋值操作。
    3. apply(target, thisArg, argumentsList):拦截对目标函数的调用操作。
    4. has(target, property):拦截in运算符判断属性是否存在于目标对象中。
    5. deleteProperty(target, property):拦截对目标对象属性的删除操作。

    以下是一个简单示例,展示了如何使用ES6 Proxy来实现一个简单的权限控制:

    1. const user = {
    2. name: "John",
    3. isAdmin: false,
    4. };
    5. const userProxy = new Proxy(user, {
    6. get(target, property) {
    7. if (property === "isAdmin") {
    8. return false; // 拒绝访问isAdmin属性
    9. }
    10. return target[property];
    11. },
    12. set(target, property, value) {
    13. if (property === "isAdmin") {
    14. throw new Error("Cannot modify isAdmin property.");
    15. }
    16. target[property] = value;
    17. return true;
    18. },
    19. });
    20. console.log(userProxy.name); // 输出: "John"
    21. console.log(userProxy.isAdmin); // 输出: false
    22. userProxy.isAdmin = true; // 抛出错误: "Cannot modify isAdmin property."

    在上述示例中,我们创建了一个名为user的普通对象,并使用Proxy对象创建了一个名为userProxy的代理对象。在代理对象的处理程序中,我们拦截了对isAdmin属性的读取和赋值操作,并进行了相应的权限控制。

    ES6 Proxy提供了强大的拦截能力,可以用于实现数据校验、权限控制、数据劫持等功能。然而,需要注意使用Proxy时要考虑性能问题,因为每个操作都会经过拦截处理。

    优缺点

    优点
    1. 代理模式可以实现对目标对象的访问控制,可以在不改变目标对象的情况下增加额外的功能。
    2. 通过使用代理模式,可以实现客户端与目标对象之间的解耦,提高代码的可维护性和可扩展性。
    3. 代理模式可以隐藏目标对象的具体实现细节,保护目标对象的安全性。
    缺点
    1. 代理模式增加了系统的复杂性,引入了额外的代理对象。
    2. 在一些情况下,代理模式可能会导致请求的延迟,因为请求需要经过代理对象转发。

    总结

    代理模式是一种常用的设计模式,它通过创建一个代理对象来控制对另一个对象的访问。通过使用代理模式,可以实现对目标对象的访问控制、增加额外功能、解耦客户端与目标对象等。然而,需要根据具体情况权衡使用代理模式所带来的优缺点。

  • 相关阅读:
    利用一款好的工具,让您轻轻松松松搭建完美系统
    大数据:Shell的操作(2)
    redis
    C++ 单例模式
    面对新的挑战,成为更好的自己--进击的技术er
    1024程序员节主题征文 | 35种语言输出1024
    XSS-labs通关游戏
    两数相加(leetcode 2)
    安科瑞为工业能效提升行动计划提供EMS解决方案
    Python创建增量目录的代码实例
  • 原文地址:https://blog.csdn.net/wanghongpu9305/article/details/133267652