代理模式
约 718 字
代理模式
核心思想
代理模式允许控制对另一对象的访问。
典型用例
保护代理
控制对原始对象的访问,用于不同权限的访问控制。保护代理根据访问者的权限决定是否允许访问真实对象。
在这个例子中,保护代理根据用户角色来决定是否允许访问。这样的设计可以用来在不同层级的应用程序中实现权限控制,而不必修改真实对象的代码。
// npm run code src/code/design-pattern/proxy/protection-agent.ts
export {};
// 定义真实对象和代理的共同接口
interface SensitiveOperation {
performOperation(): void;
}
// 创建真实对象类
class SensitiveObject implements SensitiveOperation {
performOperation(): void {
console.log("Performing a sensitive operation.");
}
}
// 创建保护代理类
class ProtectedProxy implements SensitiveOperation {
private sensitiveObject: SensitiveObject;
private hasAccess: boolean;
constructor(userRole: string) {
this.sensitiveObject = new SensitiveObject();
this.hasAccess = userRole === "admin"; // 假设只有管理员有权限
}
performOperation(): void {
if (this.hasAccess) {
this.sensitiveObject.performOperation();
} else {
console.log("Access denied. You do not have permission to perform this operation.");
}
}
}
const adminProxy = new ProtectedProxy("admin");
adminProxy.performOperation(); // 输出: Performing a sensitive operation.
const userProxy = new ProtectedProxy("user");
userProxy.performOperation(); // 输出: Access denied. You do not have permission to perform this operation.
远程代理
代理模式可以为远程对象提供一个本地的代理,以便可以像访问本地对象一样访问远程对象。例如,在分布式对象通信中,远程代理可以隐藏网络相关的复杂性。
// npm run code src/code/design-pattern/proxy/remote-agent.ts
export {};
interface IRemoteService {
fetchData(): Promise<string>;
}
class RemoteService implements IRemoteService {
async fetchData(): Promise<string> {
// 模拟网络延迟
await new Promise(resolve => setTimeout(resolve, 1000));
return "Data from remote service";
}
}
class RemoteServiceProxy implements IRemoteService {
private service: RemoteService;
constructor() {
this.service = new RemoteService();
}
async fetchData(): Promise<string> {
console.log("Proxy: Delegating fetching data to remote service...");
const data = await this.service.fetchData();
console.log("Proxy: Data fetched from remote service.");
return data;
}
}
async function clientCode(service: IRemoteService) {
const data = await service.fetchData();
console.log(`Client: Received data: ${data}`);
}
const proxy = new RemoteServiceProxy();
clientCode(proxy);
虚拟代理
使用虚拟代理可以用于延迟创建开销较大的对象。当对象的创建成本很高时,虚拟代理先代表真实对象存在,直到真正需要对象时才创建它。例如,在图像加载中,直到图像真正需要显示在屏幕上时才加载。
// npm run code src/code/design-pattern/proxy/virtual-agent.ts
export {};
interface ExpensiveObject {
performOperation(): void;
}
class ConcreteExpensiveObject implements ExpensiveObject {
constructor() {
console.log("ConcreteExpensiveObject: Initialized (heavy operation)");
}
performOperation(): void {
console.log("ConcreteExpensiveObject: Performing operation");
}
}
class VirtualProxyExpensiveObject implements ExpensiveObject {
private expensiveObject: ConcreteExpensiveObject | null = null;
performOperation(): void {
if (!this.expensiveObject) {
console.log("VirtualProxyExpensiveObject: Lazily initializing ConcreteExpensiveObject");
this.expensiveObject = new ConcreteExpensiveObject();
}
this.expensiveObject.performOperation();
}
}
function clientCode(expensiveObject: ExpensiveObject) {
console.log("Client: Executing operation.");
expensiveObject.performOperation();
}
const virtualProxy = new VirtualProxyExpensiveObject();
clientCode(virtualProxy); // 只有在这里调用时,ConcreteExpensiveObject 才会被创建
智能引用代理
智能引用代理通常需要创建一个代理类,这个类在访问实际对象时执行额外的操作,这种代理可以用来跟踪对象的引用次数、预加载资源、进行权限检查,或者执行其他在直接访问对象之前需要的操作。
// npm run code src/code/design-pattern/proxy/intelligent-reference-agent.ts
export {};
interface Subject {
performAction(): void;
}
class RealSubject implements Subject {
performAction(): void {
console.log("RealSubject: Performing action");
}
}
class SmartReferenceProxy implements Subject {
private realSubject: RealSubject;
private accessCount: number = 0;
constructor(realSubject: RealSubject) {
this.realSubject = realSubject;
}
performAction(): void {
this.accessCount++;
console.log(`SmartReferenceProxy: Access count is ${this.accessCount}`);
// 在调用真实对象之前可以执行一些额外的操作
console.log("SmartReferenceProxy: Additional actions before calling RealSubject");
this.realSubject.performAction();
// 在调用真实对象之后也可以执行一些额外的操作
console.log("SmartReferenceProxy: Additional actions after calling RealSubject");
}
}
function clientCode(subject: Subject) {
subject.performAction();
}
const realSubject = new RealSubject();
const proxy = new SmartReferenceProxy(realSubject);
clientCode(proxy); // 第一次调用
clientCode(proxy); // 第二次调用
缓存代理
当一个操作的结果被请求多次时,缓存代理可以直接从缓存中返回结果,而不是重新执行昂贵的操作。缓存代理可以为昂贵的操作结果提供临时存储,以便多个客户端可以共享这些结果,从而减少计算或网络延迟。
// npm run code src/code/design-pattern/proxy/cache-proxy.ts
export {};
interface IService {
fetchData(param: string): Promise<string>;
}
class Service implements IService {
async fetchData(param: string): Promise<string> {
console.log(`Service: Fetching data for ${param} (expensive operation)`);
// 模拟网络请求或其他昂贵操作
await new Promise(resolve => setTimeout(resolve, 1000));
return `Data for ${param}`;
}
}
class CachingProxy implements IService {
private service: Service;
private cache: Map<string, string>;
constructor(service: Service) {
this.service = service;
this.cache = new Map();
}
async fetchData(param: string): Promise<string> {
if (this.cache.has(param)) {
console.log(`CachingProxy: Returning cached data for ${param}`);
return this.cache.get(param)!;
}
const data = await this.service.fetchData(param);
this.cache.set(param, data);
console.log(`CachingProxy: Cache updated for ${param}`);
return data;
}
}
async function clientCode(service: IService) {
console.log(await service.fetchData("param1"));
// 第二次调用相同参数时,将从缓存中获取数据
console.log(await service.fetchData("param1"));
}
const service = new Service();
const proxy = new CachingProxy(service);
clientCode(proxy);
日志记录代理
日志代理可以记录一个对象的所有操作。通过代理模式,可以在执行操作的同时,自动记录每次操作的详细信息,例如,记录对数据库的查询。
// npm run code src/code/design-pattern/proxy/logging-agent.ts
export {};
interface IService {
performTask(action: string): void;
}
class Service implements IService {
performTask(action: string): void {
console.log(`Service: Performing task '${action}'`);
}
}
class LoggingProxy implements IService {
private service: Service;
private log: string[] = [];
constructor(service: Service) {
this.service = service;
}
performTask(action: string): void {
const logMessage = `LoggingProxy: Task '${action}' performed at ${new Date().toISOString()}`;
this.log.push(logMessage);
console.log(logMessage);
this.service.performTask(action);
}
getLog(): string[] {
return this.log;
}
}
function clientCode(service: IService) {
service.performTask("Task1");
service.performTask("Task2");
}
const realService = new Service();
const proxy = new LoggingProxy(realService);
clientCode(proxy);
console.log("Logged Operations:");
console.log(proxy.getLog().join("\n"));
防火墙代理
防火墙代理可以决定哪些网络请求是安全的,哪些应该被拒绝。防火墙代理充当客户端和资源之间的中介,可以基于预定义的规则允许或拒绝对资源的访问,防止不安全的或不受信任的请求访问关键资源。
// npm run code src/code/design-pattern/proxy/firewall-agent.ts
export {};
interface INetworkService {
fetchData(request: string): Promise<string>;
}
class NetworkService implements INetworkService {
async fetchData(request: string): Promise<string> {
console.log(`NetworkService: Fetching data for request: ${request}`);
// 模拟网络请求
await new Promise(resolve => setTimeout(resolve, 1000));
return `Data for ${request}`;
}
}
class FirewallProxy implements INetworkService {
private networkService: NetworkService;
private bannedRequests: Set<string>;
constructor(networkService: NetworkService) {
this.networkService = networkService;
this.bannedRequests = new Set(["badRequest", "unauthorizedRequest"]);
}
async fetchData(request: string): Promise<string> {
if (this.bannedRequests.has(request)) {
console.log(`FirewallProxy: Access denied for request: ${request}`);
throw new Error("Request blocked by firewall");
}
return await this.networkService.fetchData(request);
}
}
async function clientCode(service: INetworkService) {
try {
console.log(await service.fetchData("goodRequest"));
console.log(await service.fetchData("badRequest"));
} catch (error) {
console.error(`Error: ${(error as Error).message}`);
}
}
const service = new NetworkService();
const firewallProxy = new FirewallProxy(service);
clientCode(firewallProxy);