【设计模式】之代理模式

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

✨ 专栏介绍

设计模式是在软件开发中经过验证的解决问题的方法。它们是从经验中总结出来的,可以帮助我们更好地组织和管理代码,提高代码的可维护性、可扩展性和可重用性。无论是前端还是后端开发,设计模式都扮演着重要的角色。在本专栏中,我们将探索一些常见的前端设计模式,并学习如何将它们应用于实际项目中。通过掌握这些设计模式,我们可以编写更优雅、可靠且易于维护的前端代码。

本文主要讲解结构型模式中的代理模式


代理模式特性

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

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

前端应用示例

请求代理

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

// 定义目标对象接口classSubject {
request() {
// 处理请求  }
}
// 定义具体目标对象类classRealSubjectextendsSubject {
request() {
// 处理真实请求  }
}
// 定义代理对象类classProxyextendsSubject {
constructor() {
super();
this.realSubject=newRealSubject();
  }
request() {
// 在转发请求之前或之后执行一些额外操作this.preRequest();
this.realSubject.request();
this.postRequest();
  }
preRequest() {
// 在转发请求之前执行一些额外操作  }
postRequest() {
// 在转发请求之后执行一些额外操作  }
}
// 使用示例constproxy=newProxy();
proxy.request(); // 通过代理对象发送请求,并在转发前后执行额外操作

图片懒加载

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

// 定义目标对象classImageLoader {
constructor(imageElement) {
this.imageElement=imageElement;
this.realImage=newImage();
this.realImage.onload= () => {
this.imageElement.src=this.realImage.src;
    };
  }
load() {
// 模拟从服务器加载真实图片的操作console.log("Loading real image...");
this.realImage.src=this.imageElement.dataset.src;
  }
}
// 定义图片懒加载代理对象classLazyImageProxy {
constructor(imageElement) {
this.imageElement=imageElement;
  }
load() {
if (this.imageElement.getBoundingClientRect().top<window.innerHeight) {
constimageLoader=newImageLoader(this.imageElement);
imageLoader.load();
    }
  }
}
// 使用示例constlazyImages=document.querySelectorAll(".lazy-image");
lazyImages.forEach((image) => {
constlazyImageProxy=newLazyImageProxy(image);
lazyImageProxy.load();
});

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

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

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

数据缓存代理

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

// 定义目标对象classDataService {
fetchData(key) {
// 模拟从服务器获取数据的操作console.log("Fetching data from server...");
return`Data for ${key}`;
  }
}
// 定义数据缓存代理对象classDataCacheProxy {
constructor() {
this.cache= {};
this.dataService=newDataService();
  }
fetchData(key) {
if (this.cache[key]) {
console.log("Fetching data from cache...");
returnthis.cache[key];
    } else {
constdata=this.dataService.fetchData(key);
this.cache[key] =data;
returndata;
    }
  }
}
// 使用示例constproxy=newDataCacheProxy();
console.log(proxy.fetchData("example")); // 从服务器获取数据,并缓存起来console.log(proxy.fetchData("example")); // 从缓存中获取数据

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

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

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

ES6的Proxy

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

Proxy对象的基本语法如下:

constproxy=newProxy(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来实现一个简单的权限控制:

constuser= {
name: "John",
isAdmin: false,
};
constuserProxy=newProxy(user, {
get(target, property) {
if (property==="isAdmin") {
returnfalse; // 拒绝访问isAdmin属性    }
returntarget[property];
  },
set(target, property, value) {
if (property==="isAdmin") {
thrownewError("Cannot modify isAdmin property.");
    }
target[property] =value;
returntrue;
  },
});
console.log(userProxy.name); // 输出: "John"console.log(userProxy.isAdmin); // 输出: falseuserProxy.isAdmin=true; // 抛出错误: "Cannot modify isAdmin property."

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

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

优缺点

优点

  1. 代理模式可以实现对目标对象的访问控制,可以在不改变目标对象的情况下增加额外的功能。
  2. 通过使用代理模式,可以实现客户端与目标对象之间的解耦,提高代码的可维护性和可扩展性。
  3. 代理模式可以隐藏目标对象的具体实现细节,保护目标对象的安全性。

缺点

  1. 代理模式增加了系统的复杂性,引入了额外的代理对象。
  2. 在一些情况下,代理模式可能会导致请求的延迟,因为请求需要经过代理对象转发。

总结

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


目录
相关文章
|
4月前
|
设计模式 缓存 监控
【设计模式系列笔记】代理模式
代理模式是一种结构型设计模式,它允许一个对象(代理对象)控制另一个对象的访问。代理对象通常充当客户端和实际对象之间的中介,用于对实际对象的访问进行控制、监控或其他目的。
68 1
|
4月前
|
设计模式 缓存 安全
小谈设计模式(8)—代理模式
小谈设计模式(8)—代理模式
|
5天前
|
设计模式 缓存 安全
设计模式——代理模式
静态代理、JDK动态代理、Cglib 代理
设计模式——代理模式
|
4月前
|
设计模式 Java
Java一分钟之-设计模式:装饰器模式与代理模式
【5月更文挑战第17天】本文探讨了装饰器模式和代理模式,两者都是在不改变原有对象基础上添加新功能。装饰器模式用于动态扩展对象功能,但过度使用可能导致类数量过多;代理模式用于控制对象访问,可能引入额外性能开销。文中通过 Java 代码示例展示了两种模式的实现。理解并恰当运用这些模式能提升代码的可扩展性和可维护性。
49 1
|
4月前
|
设计模式 Java 数据库连接
【重温设计模式】代理模式及其Java示例
【重温设计模式】代理模式及其Java示例
|
1月前
|
设计模式 缓存 Java
【十一】设计模式~~~结构型模式~~~代理模式(Java)
文章详细介绍了代理模式(Proxy Pattern),这是一种对象结构型模式,用于给对象提供一个代理以控制对它的访问。文中阐述了代理模式的动机、定义、结构、优点、缺点和适用环境,并探讨了远程代理、虚拟代理、保护代理等不同代理形式。通过一个商务信息查询系统的实例,展示了如何使用代理模式来增加身份验证和日志记录功能,同时保持客户端代码的无差别对待。此外,还讨论了代理模式在分布式技术和Spring AOP中的应用,以及动态代理的概念。
【十一】设计模式~~~结构型模式~~~代理模式(Java)
|
1月前
|
设计模式
设计模式的基础问题之代理模式在工作中的问题如何解决
设计模式的基础问题之代理模式在工作中的问题如何解决
|
2月前
|
设计模式 算法 Go
iLogtail设计模式问题之代理模式在iLogtail中是如何应用的
iLogtail设计模式问题之代理模式在iLogtail中是如何应用的
|
2月前
|
设计模式 缓存 JavaScript
js设计模式【详解】—— 代理模式
js设计模式【详解】—— 代理模式
23 0
|
3月前
|
设计模式 监控 安全
设计模式之代理模式(Java)
设计模式之代理模式(Java)