结构型模式之代理模式

一、概述

1、代理模式:给某一个对象提供一个代理或占位符,并由代理对象来控制对原对象的访问。

2、代理对象在客户端和目标对象之间起到中介作用

3、引入一个新的代理对象,代理模式的主要目的是在不改变原始对象接口的前提下,增加额外的逻辑或控制

4、去掉客户不能看到的内容和服务或者增添客户需要的额外的新服务

二、代理模式的结构

代理模式包含以下三个角色:

1、Subject(抽象主题角色):定义了实际对象(RealSubject)和代理对象(Proxy)共同实现的接口。这个接口定义了实际对象的行为

2、Proxy(代理主题角色):同样实现了Subject接口,但它并不直接实现功能。相反,它持有(RealSubject)的引用,并在需要时代表(RealSubject)执行操作。代理对象可以在调用(RealSubject)的方法之前或之后,添加额外的逻辑,例如权限检查等。

3、RealSubject(真实主题角色):实现了Subject接口,定义了实际的功能

三、UML图

结构型模式之代理模式_第1张图片

四、代理模式实现的步骤

1、定义接口(Subject)

首先,定义一个接口类,该接口声明了代理类和目标类需要实现的公共方法。这个接口定义了代理模式的通用约定,确保客户端代码可以一致地与代理类和目标类进行交互。

class Subject
{
public:
	virtual ~Subject() = default;
	virtual void request() const = 0;
};

2、创建被代理类(RealSubject)

其次,创建被代理类(RealSubject),并实现接口中声明的方法。被代理类负责实际的功能实现,并包含客户端所需的具体业务逻辑

class RealSubject : public Subject
{
public:
	void request() const override
	{
		//实现具体的业务逻辑
		cout << "RealSubject: Handling request" << endl;
	}
};

3、创建代理类(ProxySubject)

然后,创建需要的代理类,代理类同样实现定义的接口。在代理类的方法中,可以添加额外的逻辑或控制。这些额外的逻辑可以在调用被代理类方法之前或之后。

class Proxy : public Subject
{
public:
	Proxy() : m_realSubject(std::make_shared()){}

	void request() const override
	{
		cout << "Proxy : Logging request" << endl;
		m_realSubject->request();
		cout << "record : Logging request" << endl;
	}

private:
	std::shared_ptr m_realSubject;
};

4、使用代理

最后,客户端代码通过代理类与被代理类交互。客户端不需要知道代理类的存在,只需要关心接口定义的方法。代理类负责在客户端与被代理类之间传递请求,并在必要时添加额外的逻辑或控制

int main()
{
	std::shared_ptr proxy = std::make_shared();
	proxy->request();

	return 0;
}

四、代理模式的应用场景

1、远程代理:在分布式系统中,远程代理可以代表远程对象的本地代理,从而隐藏远程访问的复杂性。它使得客户端可以像使用本地对象一样使用远程对象

2、延迟加载(懒加载):当一个对象的创建成本很高,或者它的初始化过程很复杂时,可以使用代理模式来延迟对象的创建。代理对象在真正需要时才会创建实际对象,从而提高系统的性能和效率。

3、访问控制代理模式可以控制对真实对象的访问权限。例如,可以在代理中添加权限检查,以确保只有授权用户才能访问真实对象。这在系统安全性要求较高的场景中尤为重要。

4、缓存:代理可以在内存中缓存真实对象的结果,以提高性能。例如,网络请求的代理可以缓存之前的请求结果,以避免重复的网络访问。

5、日志记录在代理对象中添加日志记录功能,记录对真实对象的访问情况。这对于调试和监控系统行为非常有用。

6、智能引用:代理模式可以提供对真实对象的智能引用,例如引用计数。当多个代理对象共享一个真实对象时,代理可以负责管理真实对象的生命周期,确保在不再需要时正确释放资源。

7、虚拟代理:当真实对象的创建开销很大或很复杂时,虚拟代理可以提供一个虚拟的对象占位符,直到真正需要对象时才会进行创建。

五、代理模式应用于远程代理

远程代理的实现中,代理模式通常会创建一个本地代理对象,该对象充当与远程对象进行交互的中介。这个本地代理对象负责处理与远程对象的通信,包括数据的序列化和反序列化、通过网络发送请求以及接收响应等。下面是一个简单的 C++ 示例,演示了如何使用代理模式来实现远程代理:

1、定义接口

首先,定义一个接口,声明远程对象和本地代理都需要实现的方法

class RemoteSubject
{
public:
	virtual ~RemoteSubject() = default;
	virtual void request() const = 0;
};

2、实现目标对象

通常,目标对象是远程服务器上实际存在的类。由于这个目标对象在本地不可直接访问,我们通常会将其实现放在服务器端。

class RealRemoteSubject : public RemoteSubject
{
public:
	void request() const override
	{
		cout << "RealRemoteSubject: Handling request on server" << endl;
	}
	//服务器端代码通常会包括网络通信的设备和管理,但这里为了简化示例,省略了这些部分
};

3、实现代理类

代理类在客户端与远程对象之间进行中介,处理与远程对象的通信细节

//假设我们有一个简单的网络通信库来发送请求到服务器
class NetWorkClient
{
public:
	void sendRequest() const
	{
		cout << "NetWorkClient: sending request to the server..." << endl;
	}

	void receiveResponse() const
	{
		cout << "NetWorkClient: Reveiving response from the server..." << endl;
	}
};

class ProxyRemoteSubject : public RemoteSubject
{
public:
	ProxyRemoteSubject() : m_netWorkClient(std::make_shared()) {}

	void request() const override
	{
		//代理类负责将请求转发到远程对象
		m_netWorkClient->sendRequest();

		//在实际应用中,可能需要序列化请求数据,并通过网络发送
		//网络操作可能会包括使用 socket、HTTP请求等

		cout << "ProxyRemoteSubject: Request forwarded to the server..." << endl;

		//接受远程服务器的响应
		m_netWorkClient->receiveResponse();

		//在实际应用中,可能需要处理响应数据
		//比如解析服务器返回的数据,或将响应转换为结果
	}
private:
	std::shared_ptr m_netWorkClient;
};

4、客户端代码

客户端通过代理类与远程对象交互,代理类处理所有的网络通信细节

int main()
{
	std::shared_ptr< RemoteSubject> proxy = std::make_shared();
	proxy->request();
}

5、总结

在远程代理模式中,ProxyRemoteSubject 类的作用是充当客户端和远程象 RealRemoteSubject 之间的中介。它不直接处理 RealRemoteSubject 的方法调用而是通过网络通信将请求转发给远程服务器上的 RealRemoteSubject

六、代理模式应用于访问控制

#include 
#include 
#include 

// 定义接口
class Subject {
public:
    virtual ~Subject() = default;
    virtual void request() const = 0;
};

// 目标对象
class RealSubject : public Subject {
public:
    void request() const override {
        std::cout << "RealSubject: Handling request." << std::endl;
    }
};

// 保护代理
class ProtectionProxy : public Subject {
private:
    std::shared_ptr realSubject;
    std::string userRole;

public:
    ProtectionProxy(const std::string& role) 
        : realSubject(std::make_shared()), userRole(role) {}

    void request() const override {
        if (userRole == "admin") {
            realSubject->request();
        } else {
            std::cout << "ProtectionProxy: Access denied." << std::endl;
        }
    }
};

int main() {
    std::shared_ptr proxy1 = std::make_shared("admin");
    proxy1->request();

    std::shared_ptr proxy2 = std::make_shared("user");
    proxy2->request();

    return 0;
}

七、模式优点

1、能够协调调用者和被调用者,在一定程度上降低了系统的耦合度

2、客户端可以针对抽象主题角色进行编程,增加和更好代理类无须修改源代码,符合开闭原则,系统具有更好的灵活性和可扩展性

八、模式缺点

1、由于在客户端和真实主题之间增加了代理对象,因此有些类型的代理模式可能会造成请求的处理速度变慢(例如保护代理)

2、实现代理模式需要额外的工作,而且有些代理模式的实现过程较为复杂(列如远程代理)

你可能感兴趣的:(设计模式,代理模式)