C++代理模式探索:在复杂系统中发挥控制与保护的作用

本文涉及的产品
访问控制,不限时长
简介: C++代理模式探索:在复杂系统中发挥控制与保护的作用

引言

  • 设计模式的重要性
    设计模式是一种描述软件设计中的最佳实践的方法,它们能帮助我们构建具有良好可维护性、可扩展性和复用性的软件。了解并运用设计模式能够使我们的代码更加简洁、灵活,提高编码效率和降低出错的概率。
  • 代理模式简介与应用场景
    代理模式(Proxy Pattern)是一种结构型设计模式,它为其他对象提供一种代理以控制对这个对象的访问。代理模式主要应用于如下场景:访问控制、资源优化、远程访问、延迟加载等。通过代理模式,我们可以在不改变原始对象的基础上,增加额外的功能和处理逻辑。
  • 代理模式在现代软件设计中的地位与价值
    代理模式在现代软件设计中的地位不可忽视。许多现代软件系统,如Web服务、数据库访问、安全系统等,都需要使用代理模式来实现访问控制和资源优化。通过合理运用代理模式,我们可以实现对系统的模块化和解耦,使得各个模块更容易扩展和维护。代理模式也可以帮助我们提高软件的性能、安全性和可用性。

代理模式基本概念

  • 代理模式UML图代理模式(Proxy Pattern)涉及到两个关键角色:代理类(Proxy)和实际类(RealSubject)。代理类通过持有实际类的引用,可以实现对实际类的访问控制、延迟加载等功能。客户端通过与代理类进行交互,从而间接地访问实际类。以下是C++代理模式的UML图:
+------------------+         +---------------------+
|    <<interface>> |         |      <<class>>      |
|      Subject     |         |      RealSubject    |
+------------------+         +---------------------+
| + request() : void|         | + request() : void   |
+------------------+         +---------------------+
           ^
           |
           |
+---------------------+
|      <<class>>      |
|       Proxy         |
+---------------------+
| - real_subject: RealSubject* |
| + request() : void   |
| + set_real_subject(RealSubject*) : void |
+---------------------+
  • 在这个UML图中,有三个关键组件:
  1. Subject(接口):这是一个接口,它定义了代理类(Proxy)和实际类(RealSubject)共有的方法。在C++中,可以使用纯虚函数(pure virtual function)来实现接口。
  2. RealSubject(实际类):这是实际执行操作的类,它实现了Subject接口。
  3. Proxy(代理类):这个类实现了Subject接口,并持有一个指向RealSubject对象的指针。代理类可以根据需要控制对RealSubject的访问,例如通过懒加载、访问控制等手段。客户端通过代理类间接地访问RealSubject。
  • 代理模式的定义与核心思想
    代理模式(Proxy Pattern)是指为一个对象提供一种代理,以控制对这个对象的访问。代理对象可以在客户端和目标对象之间起到一个中介的作用,并可以添加额外的功能。核心思想在于将对象的访问封装在代理对象中,以达到对目标对象的访问进行控制和扩展的目的。
  • 静态代理与动态代理的比较
    静态代理是指代理类和目标类在编译期间就已经确定,代理类需要为每一个具体的目标类编写相应的代码。优点是实现简单,易于理解;缺点是当目标类较多时,需要为每个目标类创建代理类,造成代码冗余。
    动态代理则是在运行时动态生成代理类的字节码,并加载到JVM中。优点是代理类的生成不依赖于具体的目标类,可以实现通用的代理逻辑;缺点是实现复杂,需要深入了解字节码操作和反射机制。
  • 设计原则与代理模式的关系
    代理模式遵循“开闭原则”和“单一职责原则”。通过将目标对象的访问逻辑与具体功能分离,代理模式能够实现对现有代码的封装和扩展,而无需修改原始对象的代码。此外,代理对象专注于实现访问控制和额外功能,而目标对象专注于实现核心业务逻辑,使得每个类的职责更加清晰。

静态代理实现

  • 静态代理模式的UML图静态代理模式的UML图包括以下四个主要角色:
  1. Subject(抽象主题):定义目标对象和代理对象共有的接口,以便在任何使用目标对象的地方都能使用代理对象。
  2. RealSubject(具体主题):实现Subject接口,完成实际的业务逻辑。
  3. Proxy(代理):实现Subject接口,并持有RealSubject对象的引用,可以在调用实际业务逻辑前后添加额外的逻辑。
  4. Client(客户端):与Subject接口交互,可以透明地使用代理或实际对象。
  • 静态代理模式的实现步骤
  1. 创建一个Subject接口,定义公共的方法。
  2. 创建一个RealSubject类,实现Subject接口,并完成实际的业务逻辑。
  3. 创建一个Proxy类,实现Subject接口,同时持有一个RealSubject对象的引用。
  4. 在Proxy类中,实现Subject接口的方法,并在调用RealSubject对象的方法前后添加额外的逻辑。
  5. 在Client类中,使用Proxy对象代替RealSubject对象进行操作。
  • 静态代理模式的示例代码与解析
// Subject接口
public interface Subject {
    void request();
}
// RealSubject类
public class RealSubject implements Subject {
    @Override
    public void request() {
        System.out.println("RealSubject: Handling request.");
    }
}
// Proxy类
public class Proxy implements Subject {
    private RealSubject realSubject;
    public Proxy(RealSubject realSubject) {
        this.realSubject = realSubject;
    }
    @Override
    public void request() {
        System.out.println("Proxy: Pre-processing.");
        realSubject.request();
        System.out.println("Proxy: Post-processing.");
    }
}
// Client类
public class Client {
    public static void main(String[] args) {
        RealSubject realSubject = new RealSubject();
        Proxy proxy = new Proxy(realSubject);
        proxy.request();
    }
}

动态代理实现

  • 动态代理模式的UML图动态代理模式的UML图包括以下四个主要角色:
  1. Subject(抽象主题):定义目标对象和代理对象共有的接口,以便在任何使用目标对象的地方都能使用代理对象。
  2. RealSubject(具体主题):实现Subject接口,完成实际的业务逻辑。
  3. InvocationHandler(调用处理器):负责处理代理对象的方法调用,并在调用实际业务逻辑前后添加额外的逻辑。
  4. Client(客户端):与Subject接口交互,可以透明地使用动态生成的代理对象。
  • 动态代理模式的实现步骤
  1. 创建一个Subject接口,定义公共的方法。
  2. 创建一个RealSubject类,实现Subject接口,并完成实际的业务逻辑。
  3. 创建一个InvocationHandler类,实现java.lang.reflect.InvocationHandler接口,并持有一个RealSubject对象的引用。
  4. 在InvocationHandler类中,实现invoke()方法,并在调用RealSubject对象的方法前后添加额外的逻辑。
  5. 在Client类中,使用java.lang.reflect.Proxy类动态生成一个代理对象,并使用该代理对象代替RealSubject对象进行操作。
  • 动态代理模式的示例代码与解析
// Subject接口
public interface Subject {
    void request();
}
// RealSubject类
public class RealSubject implements Subject {
    @Override
    public void request() {
        System.out.println("RealSubject: Handling request.");
    }
}
// InvocationHandler类
public class DynamicProxyHandler implements InvocationHandler {
    private Object realSubject;
    public DynamicProxyHandler(Object realSubject) {
        this.realSubject = realSubject;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("DynamicProxy: Pre-processing.");
        Object result = method.invoke(realSubject, args);
        System.out.println("DynamicProxy: Post-processing.");
        return result;
    }
}
// Client类
public class Client {
    public static void main(String[] args) {
        RealSubject realSubject = new RealSubject();
        InvocationHandler handler = new DynamicProxyHandler(realSubject);
        Subject proxy = (Subject) Proxy.newProxyInstance(realSubject.getClass().getClassLoader(),
            realSubject.getClass().getInterfaces(), handler);
        proxy.request();
    }
}
  • 以上代码展示了一个动态代理模式的简单示例。在这个例子中,Subject接口定义了一个request()方法,RealSubject类实现了这个接口并完成实际的业务逻辑。DynamicProxyHandler类实现了InvocationHandler接口,并在调用RealSubject对象的request()方法前后添加了额外的逻辑。在Client类中,我们使用Proxy.newProxyInstance()方法动态生成一个代理对象,并使用该代理对象代替RealSubject对象进行操作。

代理模式的应用场景

  • 访问控制与权限管理
    代理模式可以用于实现访问控制和权限管理。例如,当一个系统需要对某些操作进行权限控制时,可以通过代理模式实现。代理对象在执行实际操作之前可以检查用户的权限,确保只有具有足够权限的用户才能执行特定的操作。
  • 资源优化与按需加载
    代理模式可以实现资源优化和按需加载。例如,在实现一个图片浏览器时,加载大量的高清图片可能会消耗大量的内存和网络资源。通过使用代理模式,可以在需要时才加载图片,从而节省资源。代理对象可以保存图片的URL和大小等信息,当用户真正需要查看图片时,代理对象才会从网络上下载图片并显示。
  • 保护性代理与虚拟代理
    保护性代理用于保护目标对象免受不必要的访问。例如,一个数据库系统可能需要限制对敏感数据的访问。保护性代理可以检查用户的权限,确保只有具有特定权限的用户才能访问敏感数据。
    虚拟代理可以实现按需加载和资源优化。例如,在一个文档编辑器中,用户可能会插入大量的图片。虚拟代理可以将图片的加载推迟到用户真正需要查看图片时,从而节省资源和提高程序的响应速度。

代理模式的优缺点

  • 代理模式的优势
  1. 降低耦合:代理模式实现了客户端与目标对象的解耦,客户端只需要与代理对象打交道,而无需知道目标对象的具体实现。
  2. 提高安全性:代理模式可以在执行实际操作前进行权限检查,确保只有具有特定权限的用户才能执行某些操作,从而提高系统的安全性。
  3. 延迟加载与资源优化:通过代理模式,可以实现按需加载和资源优化,从而提高系统的性能。
  4. 扩展性:代理模式的扩展性较好,可以在不修改目标对象的情况下,通过修改代理对象来实现新的功能。
  • 代理模式的局限性与不适用场景
  1. 增加系统复杂性:引入代理模式会增加系统的复杂性,因为需要实现额外的代理对象。
  2. 降低运行速度:由于引入了代理对象,程序的运行速度可能会受到一定程度的影响。
  3. 不适用于无需访问控制或按需加载的场景:如果目标对象不需要访问控制或按需加载等功能,那么引入代理模式可能会增加不必要的开销。在这种情况下,直接访问目标对象可能更为合适。

代理模式与其他设计模式的关联

  • 代理模式与装饰器模式的比较
  1. 相同点:都是结构型设计模式,它们都有一个与目标对象相同的接口,都可以在不修改目标对象的情况下进行功能扩展。
  2. 不同点:代理模式的主要目的是为目标对象提供一个替代者,以便控制目标对象的访问,比如访问控制、按需加载等。装饰器模式的主要目的是在不修改目标对象的情况下,动态地给目标对象增加职责或功能。
  • 代理模式与外观模式的比较
  1. 相同点:都是结构型设计模式,它们都为其他对象提供了一个代表或者一个接口。
  2. 不同点:代理模式为一个对象提供一个代表,以便控制该对象的访问。外观模式为一组对象提供了一个统一的接口,以便简化对这组对象的访问。
  • 代理模式与适配器模式的比较
  1. 相同点:都是结构型设计模式,它们都起到了中介的作用。
  2. 不同点:代理模式主要用于控制对目标对象的访问,而适配器模式主要用于使原本不兼容的接口能够一起工作。适配器模式关注的是接口转换,代理模式关注的是访问控制。

代理模式在C/C++中的实现

懒加载代理模式 - 用于延迟加载大型对象

class LargeObject {
public:
    void performOperation() {
        // 执行一些耗时操作
    }
};
class LargeObjectProxy {
public:
    void performOperation() {
        if (!largeObject) {
            largeObject = new LargeObject();
        }
        largeObject->performOperation();
    }
private:
    LargeObject *largeObject = nullptr;
};

远程代理模式 - 用于访问远程对象的接口

class RemoteObject {
public:
    virtual void remoteOperation() = 0;
};
class RemoteObjectImpl : public RemoteObject {
public:
    void remoteOperation() override {
        // 实际执行远程操作的代码
    }
};
class RemoteObjectProxy : public RemoteObject {
public:
    void remoteOperation() override {
        // 进行网络通信,将请求发送给远程对象
        // 并获取远程对象的结果
    }
};

保护代理模式 - 用于限制对对象的访问权限

class ProtectedObject {
public:
    virtual void restrictedOperation() = 0;
};
class ProtectedObjectImpl : public ProtectedObject {
public:
    void restrictedOperation() override {
        // 实际执行受限操作的代码
    }
};
class ProtectedObjectProxy : public ProtectedObject {
public:
    void restrictedOperation() override {
        if (checkAccessPermission()) {
            protectedObject->restrictedOperation();
        } else {
            // 拒绝执行受限操作,可能抛出异常或记录日志
        }
    }
private:
    bool checkAccessPermission() {
        // 检查访问权限,返回 true 表示允许访问
        return true;
    }
    ProtectedObject *protectedObject = new ProtectedObjectImpl();
};

访问代理模式 - 用于记录对象的访问次数和时间

#include <iostream>
#include <chrono>
class AccessibleObject {
public:
    virtual void operation() = 0;
};
class RealObject : public AccessibleObject {
public:
    void operation() override {
        // 实际执行操作的代码
        std::cout << "Real object operation performed." << std::endl;
    }
};
class AccessProxy : public AccessibleObject {
public:
    AccessProxy() : accessCount(0) {}
    void operation() override {
        auto startTime = std::chrono::high_resolution_clock::now();
        realObject.operation();
        auto endTime = std::chrono::high_resolution_clock::now();
        accessCount++;
        totalTime += std::chrono::duration_cast<std::chrono::microseconds>(endTime - startTime).count();
        std::cout << "Access count: " << accessCount << ", Total time: " << totalTime << " microseconds" << std::endl;
    }
private:
    RealObject realObject;
    int accessCount;
    long long totalTime;
};

智能指针代理模式 - 用于管理指针生命周期和内存分配

#include <iostream>
template<typename T>
class SmartPointer {
public:
    explicit SmartPointer(T *ptr) : rawPointer(ptr) {}
    
    ~SmartPointer() {
        delete rawPointer;
    }
    T *operator->() {
        return rawPointer;
    }
    T &operator*() {
        return *rawPointer;
    }
private:
    T *rawPointer;
};

缓存代理模式 - 用于提高重复操作的性能

#include <iostream>
#include <unordered_map>
class Cacheable {
public:
    virtual int expensiveOperation(int key) = 0;
};
class ExpensiveResource : public Cacheable {
public:
    int expensiveOperation(int key) override {
        // 实际执行昂贵操作的代码
        std::cout << "Performing expensive operation for key: " << key << std::endl;
        return key * 2;
    }
};
class CacheProxy : public Cacheable {
public:
    CacheProxy() : expensiveResource(new ExpensiveResource()) {}
    int expensiveOperation(int key) override {
        auto it = cache.find(key);
        if (it != cache.end()) {
            // 从缓存中获取结果
            return it->second;
        }
        // 如果缓存中没有结果,则执行昂贵操作并将结果存入缓存
        int result = expensiveResource->expensiveOperation(key);
        cache[key] = result;
        return result;
    }
private:
    ExpensiveResource *expensiveResource;
    std::unordered_map<int, int> cache;
};

日志代理模式 - 用于记录对象的操作日志和异常信息

#include <iostream>
#include <string>
#include <exception>
class Loggable {
public:
    virtual void performOperation(const std::string &operation) = 0;
};
class TargetObject : public Loggable {
public:
    void performOperation(const std::string &operation) override {
        std::cout << "Performing operation: " << operation << std::endl;
        // 执行操作代码
    }
};
class LoggingProxy : public Loggable {
public:
    LoggingProxy() : targetObject(new TargetObject()) {}
    void performOperation(const std::string &operation) override {
        try {
            std::cout << "Logging: Attempting operation: " << operation << std::endl;
            targetObject->performOperation(operation);
            std::cout << "Logging: Operation completed: " << operation << std::endl;
        } catch (const std::exception &e) {
            std::cout << "Logging: Exception occurred: " << e.what() << std::endl;
        }
    }
private:
    TargetObject *targetObject;
};

安全代理模式 - 用于防止恶意用户攻击或代码注入

#include <iostream>
#include <string>
#include <vector>
class Securable {
public:
    virtual void restrictedOperation(const std::string &operation) = 0;
};
class SecureObject : public Securable {
public:
    void restrictedOperation(const std::string &operation) override {
        // 执行受限操作的代码
        std::cout << "Performing restricted operation: " << operation << std::endl;
    }
};
class SecurityProxy : public Securable {
public:
    SecurityProxy(const std::string &user, const std::string &password)
        : secureObject(new SecureObject()) {
        // 假设我们已经验证了用户和密码
        if (user == "admin" && password == "admin123") {
            authenticated = true;
        } else {
            authenticated = false;
        }
    }
    void restrictedOperation(const std::string &operation) override {
        if (authenticated) {
            secureObject->restrictedOperation(operation);
        } else {
            std::cout << "Access denied: Invalid user or password." << std::endl;
        }
    }
private:
    SecureObject *secureObject;
    bool authenticated;
};

控制访问代理模式 - 用于限制对对象的并发访问

#include <iostream>
#include <string>
#include <mutex>
class AccessControlled {
public:
    virtual void performConcurrentOperation(const std::string &operation) = 0;
};
class ControlledObject : public AccessControlled {
public:
    void performConcurrentOperation(const std::string &operation) override {
        // 执行并发操作的代码
        std::cout << "Performing concurrent operation: " << operation << std::endl;
    }
};
class AccessControlProxy : public AccessControlled {
public:
    AccessControlProxy() : controlledObject(new ControlledObject()) {}
    void performConcurrentOperation(const std::string &operation) override {
        std::unique_lock<std::mutex> lock(mutex);
        if (activeThreads < maxConcurrentThreads) {
            ++activeThreads;
            lock.unlock();
            controlledObject->performConcurrentOperation(operation);
            lock.lock();
            --activeThreads;
        } else {
            std::cout << "Access denied: Maximum number of concurrent threads reached." << std::endl;
        }
    }
private:
    ControlledObject *controlledObject;
    std::mutex mutex;
    int activeThreads = 0;
    const int maxConcurrentThreads = 3;
};

虚拟代理模式 - 用于延迟对象的初始化和加载

#include <iostream>
#include <string>
#include <memory>
class Loadable {
public:
    virtual void performOperation(const std::string &operation) = 0;
};
class ExpensiveObject : public Loadable {
public:
    ExpensiveObject() {
        // 模拟昂贵的对象初始化
        std::cout << "Initializing expensive object..." << std::endl;
    }
    void performOperation(const std::string &operation) override {
        std::cout << "Performing operation: " << operation << std::endl;
    }
};
class VirtualProxy : public Loadable {
public:
    void performOperation(const std::string &operation) override {
        if (!expensiveObject) {
            expensiveObject = std::make_unique<ExpensiveObject>();
        }
        expensiveObject->performOperation(operation);
    }
private:
    std::unique_ptr<ExpensiveObject> expensiveObject;
};

总结与展望

  • 代理模式在软件设计中的优势
  1. 代理模式可以实现对原对象的访问控制,提供了访问和修改对象的层次,保护原对象不受意外和恶意操作影响。
  2. 代理模式支持按需加载和初始化,可以有效减少程序启动时间和内存消耗,提高运行效率。
  3. 代理模式可以与原对象实现解耦,扩展和修改代理功能时,不影响原对象的实现。
  4. 代理模式支持动态代理和静态代理,可以在运行时动态创建代理,实现更灵活的代理控制。
  • 设计模式的发展趋势与前景 随着软件设计的发展和需求日益复杂化,设计模式将在未来继续演化和发展。一些新的设计模式可能会应运而生,已有的设计模式会根据实际需求和编程语言特性进行改进和优化。设计模式在软件工程中的地位和价值将继续得到重视和推广。
  • 探索更多代理模式的应用领域与可能性
  1. 在分布式系统和微服务架构中,代理模式可以用于实现服务间通信和负载均衡。
  2. 在云计算和虚拟化技术中,代理模式可以用于资源调度和访问控制。
  3. 在物联网和边缘计算领域,代理模式可以用于优化数据传输和设备访问。
  4. 在数据挖掘和机器学习中,代理模式可以用于资源优化和算法加速。
  5. 在安全领域,代理模式可以用于实现权限管理、访问控制和审计跟踪等功能。
相关实践学习
消息队列+Serverless+Tablestore:实现高弹性的电商订单系统
基于消息队列以及函数计算,快速部署一个高弹性的商品订单系统,能够应对抢购场景下的高并发情况。
云安全基础课 - 访问控制概述
课程大纲 课程目标和内容介绍视频时长 访问控制概述视频时长 身份标识和认证技术视频时长 授权机制视频时长 访问控制的常见攻击视频时长
目录
相关文章
|
4月前
|
算法 C语言 C++
C++语言学习指南:从新手到高手,一文带你领略系统编程的巅峰技艺!
【8月更文挑战第22天】C++由Bjarne Stroustrup于1985年创立,凭借卓越性能与灵活性,在系统编程、游戏开发等领域占据重要地位。它继承了C语言的高效性,并引入面向对象编程,使代码更模块化易管理。C++支持基本语法如变量声明与控制结构;通过`iostream`库实现输入输出;利用类与对象实现面向对象编程;提供模板增强代码复用性;具备异常处理机制确保程序健壮性;C++11引入现代化特性简化编程;标准模板库(STL)支持高效编程;多线程支持利用多核优势。虽然学习曲线陡峭,但掌握后可开启高性能编程大门。随着新标准如C++20的发展,C++持续演进,提供更多开发可能性。
82 0
|
3月前
|
C++
【C++案例】一个项目掌握C++基础-通讯录管理系统
这篇文章通过一个通讯录管理系统的C++项目案例,详细介绍了如何使用C++实现添加、显示、删除、查找、修改和清空联系人等功能。
44 3
|
4月前
|
存储 C++
【C++】C++ 基于QT实现散列表学生管理系统(源码+数据+课程论文)【独一无二】
【C++】C++ 基于QT实现散列表学生管理系统(源码+数据+课程论文)【独一无二】
【C++】C++ 基于QT实现散列表学生管理系统(源码+数据+课程论文)【独一无二】
|
4月前
|
Rust 安全 C++
系统编程的未来之战:Rust能否撼动C++的王座?
【8月更文挑战第31天】Rust与C++:现代系统编程的新选择。C++长期主导系统编程,但内存安全问题频发。Rust以安全性为核心,通过所有权和生命周期概念避免内存泄漏和野指针等问题。Rust在编译时确保内存安全,简化并发编程,其生态系统虽不及C++成熟,但发展迅速,为现代系统编程提供了新选择。未来有望看到更多Rust驱动的系统级应用。
67 1
|
4月前
|
存储 算法 数据可视化
【C++】C++旅游管理系统(源码+论文)【独一无二】
【C++】C++旅游管理系统(源码+论文)【独一无二】
|
4月前
|
存储 数据挖掘 C语言
【C/C++】C/C++车辆交通违章管理系统(源码+数据文件)【独一无二】
【C/C++】C/C++车辆交通违章管理系统(源码+数据文件)【独一无二】
|
4月前
|
搜索推荐 数据处理 文件存储
【C++】C++ 培训报名系统 (源码+论文)【独一无二】
【C++】C++ 培训报名系统 (源码+论文)【独一无二】
|
4月前
|
存储 C++
【C++】C++公司人事管理系统(源码)【独一无二】
【C++】C++公司人事管理系统(源码)【独一无二】
113 2
|
4月前
|
存储 数据可视化 C++
【C++】C++-机房收费管理系统(源码+注释)【独一无二】
【C++】C++-机房收费管理系统(源码+注释)【独一无二】
|
4月前
|
数据可视化 C++
【C++】C++商店销售管理系统(源码+论文)【独一无二】
【C++】C++商店销售管理系统(源码+论文)【独一无二】