C++软件设计模式之代理(Proxy)模式

Proxy 模式(代理模式)的意图、动机和适用场合

意图

Proxy 模式是一种结构型设计模式,它的主要意图是为其他对象提供一个代理以控制对这个对象的访问。通过引入代理对象,可以在不改变原有对象的基础上,增加额外的功能或限制对对象的访问。

动机
  1. 控制访问

    • 有时我们希望在访问对象之前或之后添加一些额外的处理逻辑,例如权限检查、日志记录、延迟初始化等。直接修改对象的代码可能会导致代码复杂性和维护成本的增加。使用代理模式可以在不改变对象本身的情况下,通过代理对象来实现这些功能。
  2. 性能优化

    • 对于一些资源消耗较大的对象,可以在需要时才进行初始化,并通过代理对象来管理这些对象的生命周期。这样可以避免在系统启动时就加载所有资源,从而提高性能。
  3. 远程代理

    • 在分布式系统中,客户端和服务器之间的通信可能涉及网络延迟和资源消耗。通过代理对象,可以将客户端的请求转发到服务器,并在服务器上执行相应的操作,返回结果给客户端。这样可以隐藏远程通信的复杂性。
  4. 智能引用

    • 对象的引用计数管理和自动资源释放可以通过代理对象来实现。例如,在智能指针中,代理对象可以负责管理对象的引用计数,并在引用计数为零时自动删除对象。
适用场合
  1. 延迟初始化

    • 当对象的创建和初始化过程较为复杂或资源消耗较大时,可以通过代理对象在需要时才进行初始化。例如,创建一个大型图片对象时,可以在第一次访问时才加载图片数据。
  2. 权限控制

    • 当需要在对象访问之前进行权限检查时,可以使用代理对象来实现。例如,一个文件对象在被读取或写入之前,代理对象可以检查当前用户是否有相应的权限。
  3. 日志记录

    • 当需要在对象的方法调用前后记录日志时,可以使用代理对象来实现。例如,一个数据库操作对象在执行查询或更新操作时,代理对象可以记录操作的时间和参数。
  4. 远程对象访问

    • 当需要访问远程对象时,可以使用代理对象来封装远程通信的细节。例如,一个网络服务的客户端可以通过代理对象来调用服务器上的方法。
  5. 缓存

    • 当需要缓存对象的结果以提高性能时,可以使用代理对象来实现。例如,一个昂贵的计算结果可以通过代理对象缓存起来,避免重复计算。
  6. 智能引用

    • 当需要管理对象的生命周期时,可以使用代理对象来实现引用计数管理。例如,std::shared_ptr 就是一个常见的代理模式的实现,用于管理对象的引用计数和自动资源释放。

示例代码:延迟初始化和权限控制

假设我们有一个大型的图像对象,我们希望在第一次访问时才加载图像数据,并且在访问之前进行权限检查。

1. 定义主题接口
#include <iostream>
#include <string>
#include <memory>

class Image {
public:
    virtual void draw() const = 0;
    virtual ~Image() {}
};

class RealImage : public Image {
private:
    std::string _filename;
    bool _isLoaded;
public:
    RealImage(const std::string& filename) : _filename(filename), _isLoaded(false) {}

    void draw() const override {
        if (!_isLoaded) {
            loadFromDisk();
        }
        std::cout << "绘制图像: " << _filename << std::endl;
    }

private:
    void loadFromDisk() const {
        std::cout << "加载图像: " << _filename << " 从磁盘" << std::endl;
        _isLoaded = true;
    }
};

2. 定义代理类
class ImageProxy : public Image {
private:
    std::string _filename;
    mutable std::unique_ptr<RealImage> _realImage;
public:
    ImageProxy(const std::string& filename) : _filename(filename), _realImage(nullptr) {}

    void draw() const override {
        checkAccess();
        _realImage = std::make_unique<RealImage>(_filename);
        _realImage->draw();
    }

private:
    void checkAccess() const {
        std::cout << "检查权限: " << _filename << std::endl;
        // 这里可以添加实际的权限检查逻辑
        std::cout << "权限检查通过" << std::endl;
    }
};

3. 客户端代码
int main() {
    ImageProxy proxy("large_image.jpg");

    // 第一次调用 draw,会进行权限检查和图像加载
    proxy.draw();

    // 第二次调用 draw,不再进行图像加载
    proxy.draw();

    return 0;
}

代码解释

  1. Image 接口

    • 定义了一个 draw 方法,用于绘制图像。
  2. RealImage 类

    • 实现了 Image 接口,具体的 draw 方法在绘制图像之前会检查图像是否已经加载,如果尚未加载,则从磁盘加载图像数据。
  3. ImageProxy 类

    • 也实现了 Image 接口,但它的 draw 方法在实际绘制图像之前会进行权限检查。
    • 如果权限检查通过,代理对象会创建一个 RealImage 对象并调用其 draw 方法。
    • checkAccess 方法用于进行权限检查,实际应用中可以添加具体的权限检查逻辑。
    • mutable 关键字用于允许 const 方法修改 _realImage,因为代理对象的 draw 方法可以在 const 环境下调用。
  4. 客户端代码

    • 创建 ImageProxy 对象,指定图像文件名。
    • 第一次调用 draw 方法时,代理对象会进行权限检查和图像加载。
    • 第二次调用 draw 方法时,图像已经加载,不会再进行加载操作。

权限控制

示例代码
#include <iostream>
#include <string>

// 定义主题接口
class Image {
public:
    virtual void draw() const = 0;
    virtual ~Image() = default;
};

// 具体的图像实现
class RealImage : public Image {
private:
    std::string _filename;
public:
    RealImage(const std::string& filename) : _filename(filename) {}

    void draw() const override {
        loadFromDisk();
        std::cout << "绘制图像: " << _filename << std::endl;
    }

private:
    void loadFromDisk() const {
        std::cout << "加载图像: " << _filename << " 从磁盘" << std::endl;
    }
};

// 权限控制代理
class ImageProxy : public Image {
private:
    std::string _filename;
    mutable std::unique_ptr<RealImage> _realImage;
public:
    ImageProxy(const std::string& filename) : _filename(filename), _realImage(nullptr) {}

    void draw() const override {
        if (!checkAccess()) {
            std::cout << "权限检查未通过,无法绘制图像" << std::endl;
            return;
        }
        if (!_realImage) {
            _realImage = std::make_unique<RealImage>(_filename);
        }
        _realImage->draw();
    }

private:
    bool checkAccess() const {
        std::cout << "检查权限: " << _filename << std::endl;
        // 这里可以添加实际的权限检查逻辑
        std::cout << "权限检查通过" << std::endl;
        return true;
    }
};

int main() {
    ImageProxy proxy("large_image.jpg");

    // 第一次调用 draw,会进行权限检查和图像加载
    proxy.draw();

    // 第二次调用 draw,不再进行图像加载
    proxy.draw();

    return 0;
}

日志记录

示例代码
#include <iostream>
#include <string>

// 定义主题接口
class Database {
public:
    virtual void execute(const std::string& query) = 0;
    virtual ~Database() = default;
};

// 具体的数据库实现
class RealDatabase : public Database {
public:
    void execute(const std::string& query) override {
        std::cout << "执行数据库查询: " << query << std::endl;
    }
};

// 日志记录代理
class DatabaseProxy : public Database {
private:
    std::unique_ptr<RealDatabase> _realDatabase;
public:
    DatabaseProxy() : _realDatabase(std::make_unique<RealDatabase>()) {}

    void execute(const std::string& query) override {
        logBefore(query);
        _realDatabase->execute(query);
        logAfter(query);
    }

private:
    void logBefore(const std::string& query) {
        std::cout << "日志: 正在执行查询: " << query << std::endl;
    }

    void logAfter(const std::string& query) {
        std::cout << "日志: 查询: " << query << " 执行完成" << std::endl;
    }
};

int main() {
    DatabaseProxy proxy;

    // 执行查询
    proxy.execute("SELECT * FROM users");

    return 0;
}

远程对象访问

示例代码
#include <iostream>
#include <string>

// 定义主题接口
class Service {
public:
    virtual void processRequest(const std::string& request) = 0;
    virtual ~Service() = default;
};

// 具体的远程服务实现
class RemoteService : public Service {
public:
    void processRequest(const std::string& request) override {
        std::cout << "处理远程请求: " << request << std::endl;
    }
};

// 远程服务代理
class RemoteServiceProxy : public Service {
private:
    std::unique_ptr<RemoteService> _realService;
public:
    RemoteServiceProxy() : _realService(std::make_unique<RemoteService>()) {}

    void processRequest(const std::string& request) override {
        std::cout << "代理: 转发请求: " << request << " 到远程服务" << std::endl;
        _realService->processRequest(request);
        std::cout << "代理: 接收到远程服务的响应" << std::endl;
    }
};

int main() {
    RemoteServiceProxy proxy;

    // 处理请求
    proxy.processRequest("GET /users");

    return 0;
}

缓存

示例代码
#include <iostream>
#include <string>
#include <unordered_map>

// 定义主题接口
class DataFetcher {
public:
    virtual std::string fetchData(const std::string& key) = 0;
    virtual ~DataFetcher() = default;
};

// 具体的数据获取实现
class RealDataFetcher : public DataFetcher {
public:
    std::string fetchData(const std::string& key) override {
        std::cout << "从数据库获取数据: " << key << std::endl;
        return "Data for " + key;
    }
};

// 缓存代理
class DataFetcherProxy : public DataFetcher {
private:
    std::unique_ptr<RealDataFetcher> _realDataFetcher;
    std::unordered_map<std::string, std::string> _cache;
public:
    DataFetcherProxy() : _realDataFetcher(std::make_unique<RealDataFetcher>()) {}

    std::string fetchData(const std::string& key) override {
        if (_cache.find(key) != _cache.end()) {
            std::cout << "从缓存中获取数据: " << key << std::endl;
            return _cache[key];
        }

        std::string data = _realDataFetcher->fetchData(key);
        _cache[key] = data;
        return data;
    }
};

int main() {
    DataFetcherProxy proxy;

    // 第一次请求,从数据库获取数据
    std::cout << proxy.fetchData("user1") << std::endl;

    // 第二次请求,从缓存中获取数据
    std::cout << proxy.fetchData("user1") << std::endl;

    return 0;
}

智能引用

示例代码
#include <iostream>
#include <string>
#include <memory>

// 定义主题接口
class Resource {
public:
    virtual void use() = 0;
    virtual ~Resource() = default;
};

// 具体的资源实现
class RealResource : public Resource {
public:
    RealResource(const std::string& name) : _name(name) {
        std::cout << "创建资源: " << _name << std::endl;
    }

    ~RealResource() override {
        std::cout << "销毁资源: " << _name << std::endl;
    }

    void use() override {
        std::cout << "使用资源: " << _name << std::endl;
    }

private:
    std::string _name;
};

// 智能引用代理
class ResourceProxy : public Resource {
private:
    std::string _name;
    mutable std::shared_ptr<RealResource> _resource;
public:
    ResourceProxy(const std::string& name) : _name(name), _resource(nullptr) {}

    void use() const override {
        if (!_resource) {
            _resource = std::make_shared<RealResource>(_name);
        }
        _resource->use();
    }
};

int main() {
    ResourceProxy proxy1("resource1");
    ResourceProxy proxy2("resource2");

    // 使用资源
    proxy1.use();
    proxy2.use();

    // 再次使用资源
    proxy1.use();
    proxy2.use();

    return 0;
}

代码解释

1. 权限控制
  • Image 接口:定义了一个 draw 方法,用于绘制图像。
  • RealImage 类:实现了 Image 接口,具体的 draw 方法会从磁盘加载图像数据并绘制。
  • ImageProxy 类:实现了 Image 接口,但它的 draw 方法在实际绘制图像之前会进行权限检查。如果权限检查通过,则创建 RealImage 对象并调用其 draw 方法。
2. 日志记录
  • Database 接口:定义了一个 execute 方法,用于执行数据库查询。
  • RealDatabase 类:实现了 Database 接口,具体的 execute 方法会执行数据库查询。
  • DatabaseProxy 类:实现了 Database 接口,但它的 execute 方法在执行查询前后会记录日志。
3. 远程对象访问
  • Service 接口:定义了一个 processRequest 方法,用于处理请求。
  • RemoteService 类:实现了 Service 接口,具体的 processRequest 方法会处理远程请求。
  • RemoteServiceProxy 类:实现了 Service 接口,但它的 processRequest 方法会转发请求到远程服务,并在接收到响应后通知客户端。
4. 缓存
  • DataFetcher 接口:定义了一个 fetchData 方法,用于获取数据。
  • RealDataFetcher 类:实现了 DataFetcher 接口,具体的 fetchData 方法会从数据库获取数据。
  • DataFetcherProxy 类:实现了 DataFetcher 接口,但它的 fetchData 方法会先检查缓存。如果缓存中有数据,则直接返回;否则,从数据库获取数据并缓存起来。
5. 智能引用
  • Resource 接口:定义了一个 use 方法,用于使用资源。
  • RealResource 类:实现了 Resource 接口,具体的 use 方法会使用资源,并在对象创建和销毁时输出相应的消息。
  • ResourceProxy 类:实现了 Resource 接口,但它的 use 方法在实际使用资源之前会检查资源是否已经创建。如果尚未创建,则创建资源对象并使用;否则,直接使用已创建的资源对象。通过使用 std::shared_ptr,可以自动管理资源对象的生命周期。

通过这些示例代码,希望你能够更好地理解 Proxy 模式在不同场合下的应用。每种示例都展示了如何通过代理对象来增加额外的功能或控制对象的访问,同时保持主题接口的一致性。

保护代理模式(Protection Proxy)与装饰器模式(Decorator)的相似性与不同点

相似性
  1. 结构型设计模式

    • 保护代理模式和装饰器模式都是结构型设计模式,它们都通过在现有类的基础上添加一个新的类来扩展或控制现有类的功能。
  2. 继承或组合

    • 两种模式都通过继承现有的接口或类,或者通过组合的方式来实现扩展或控制功能。这种方式可以确保新的类与现有类在接口上保持一致,从而在客户端代码中可以无缝地替换现有类的实例。
  3. 动态性

    • 保护代理模式和装饰器模式都具有动态性,即可以在运行时决定是否添加或控制功能,而不需要在编译时对现有类进行修改。
不同点
  1. 设计意图

    • 保护代理模式:主要目的是控制对对象的访问。通过代理对象,可以在访问对象之前或之后添加权限检查、审计等逻辑,确保只有授权的客户端可以访问对象。
    • 装饰器模式:主要目的是在不改变对象接口的前提下,动态地给对象添加新的职责或行为。通过装饰器对象,可以在运行时动态地组合多个行为,从而实现功能的扩展。
  2. 功能扩展方式

    • 保护代理模式:通常只有一个代理对象,负责控制对单个对象的访问。代理对象的主要职责是权限检查和访问控制。
    • 装饰器模式:可以有多个装饰器对象,每个装饰器对象负责添加一个或多个新的职责。装饰器对象可以层层叠加,形成一个装饰器链,从而实现复杂的功能扩展。
  3. 对象状态

    • 保护代理模式:代理对象通常不会更改被代理对象的状态,只是控制访问。
    • 装饰器模式:装饰器对象可以更改被装饰对象的状态或行为,例如添加日志记录、缓存等。
  4. 代码复杂性

    • 保护代理模式:通常代码结构较为简单,因为只需要一个代理对象来控制访问。
    • 装饰器模式:代码结构可能更复杂,尤其是当需要添加多个装饰器时。每个装饰器都需要实现相同的接口,并且可以层层叠加。
示例代码对比
保护代理模式
#include <iostream>
#include <string>
#include <memory>

// 定义主题接口
class Image {
public:
    virtual void draw() const = 0;
    virtual ~Image() = default;
};

// 具体的图像实现
class RealImage : public Image {
private:
    std::string _filename;
public:
    RealImage(const std::string& filename) : _filename(filename) {}

    void draw() const override {
        loadFromDisk();
        std::cout << "绘制图像: " << _filename << std::endl;
    }

private:
    void loadFromDisk() const {
        std::cout << "加载图像: " << _filename << " 从磁盘" << std::endl;
    }
};

// 保护代理
class ImageProxy : public Image {
private:
    std::string _filename;
    mutable std::unique_ptr<RealImage> _realImage;
public:
    ImageProxy(const std::string& filename) : _filename(filename), _realImage(nullptr) {}

    void draw() const override {
        if (!checkAccess()) {
            std::cout << "权限检查未通过,无法绘制图像" << std::endl;
            return;
        }
        if (!_realImage) {
            _realImage = std::make_unique<RealImage>(_filename);
        }
        _realImage->draw();
    }

private:
    bool checkAccess() const {
        std::cout << "检查权限: " << _filename << std::endl;
        // 这里可以添加实际的权限检查逻辑
        std::cout << "权限检查通过" << std::endl;
        return true;
    }
};

int main() {
    ImageProxy proxy("large_image.jpg");

    // 第一次调用 draw,会进行权限检查和图像加载
    proxy.draw();

    // 第二次调用 draw,不再进行图像加载
    proxy.draw();

    return 0;
}

装饰器模式
#include <iostream>
#include <string>

// 定义主题接口
class Image {
public:
    virtual void draw() const = 0;
    virtual ~Image() = default;
};

// 具体的图像实现
class RealImage : public Image {
private:
    std::string _filename;
public:
    RealImage(const std::string& filename) : _filename(filename) {}

    void draw() const override {
        loadFromDisk();
        std::cout << "绘制图像: " << _filename << std::endl;
    }

private:
    void loadFromDisk() const {
        std::cout << "加载图像: " << _filename << " 从磁盘" << std::endl;
    }
};

// 装饰器基类
class ImageDecorator : public Image {
protected:
    Image* _image;
public:
    ImageDecorator(Image* image) : _image(image) {}
    void draw() const override {
        _image->draw();
    }
};

// 日志记录装饰器
class LoggingImageDecorator : public ImageDecorator {
public:
    LoggingImageDecorator(Image* image) : ImageDecorator(image) {}

    void draw() const override {
        std::cout << "日志: 开始绘制图像" << std::endl;
        _image->draw();
        std::cout << "日志: 图像绘制完成" << std::endl;
    }
};

// 压缩装饰器
class CompressImageDecorator : public ImageDecorator {
public:
    CompressImageDecorator(Image* image) : ImageDecorator(image) {}

    void draw() const override {
        std::cout << "压缩图像数据" << std::endl;
        _image->draw();
    }
};

int main() {
    RealImage* realImage = new RealImage("large_image.jpg");

    // 使用多个装饰器
    Image* compressedImage = new CompressImageDecorator(realImage);
    Image* loggingImage = new LoggingImageDecorator(compressedImage);

    // 调用 draw 方法
    loggingImage->draw();

    // 释放内存
    delete loggingImage;
    delete compressedImage;
    delete realImage;

    return 0;
}

设计意图的区别

  1. 保护代理模式

    • 设计意图:控制对对象的访问。通过代理对象,可以在不改变对象本身的情况下,增加权限检查、审计等逻辑,确保只有授权的客户端可以访问对象。
    • 适用场景:适用于需要对对象访问进行控制的场景,例如资源访问控制、安全检查等。
    • 主要职责:权限检查、访问控制。
  2. 装饰器模式

    • 设计意图:在不改变对象接口的前提下,动态地给对象添加新的职责或行为。通过装饰器对象,可以在运行时动态地组合多个行为,从而实现功能的扩展。
    • 适用场景:适用于需要动态扩展对象功能的场景,例如添加日志记录、压缩、缓存等。
    • 主要职责:动态地添加职责或行为,功能扩展。

总结

  • 相似性

    • 两者都通过继承或组合的方式扩展或控制现有类的功能。
    • 两者都保持了现有类的接口一致性,可以无缝地替换现有类的实例。
  • 不同点

    • 保护代理模式主要关注访问控制,通过代理对象在访问对象之前或之后进行权限检查或审计。
    • 装饰器模式主要关注功能扩展,通过装饰器对象在运行时动态地给对象添加新的职责或行为,可以层层叠加形成装饰器链。
  • 设计意图

    • 保护代理模式:控制对对象的访问。
    • 装饰器模式:动态地扩展对象的功能。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/942698.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

PPT画图——如何设置导致图片为600dpi

winr&#xff0c;输入regedit打开注册表 按路径找&#xff0c;HKEY_CURRENT_USER\Software\Microsoft\Office\XX.0\PowerPoint\Options&#xff08;xx为版本号&#xff0c;16.0 or 15.0或则其他&#xff09;。名称命名&#xff1a;ExportBitmapResolution 保存即可&#xff0c;…

Linux复习4——shell与文本处理

认识vim编辑器 #基本语法格式&#xff1a; vim 文件名 •如果文件存在&#xff0c;进入编辑状态对其进行编辑 •如果文件不存在&#xff0c;创建文件并进入编辑状态 例&#xff1a; [rootlocalhosttest]# vim practice.txt #Vim 编辑器三种模式&#xff1a; 命令模式&a…

Gmsh有限元网格剖分(Python)---点、直线、平面的移动

Gmsh有限元网格剖分(Python)—点、直线、平面的移动和旋转 最近在学习有限元的网格剖分算法&#xff0c;主要还是要参考老外的开源Gmsh库进行&#xff0c;写一些博客记录下学习过程&#xff0c;方便以后回忆嘞。 Gmsh的官方英文文档可以参考&#xff1a;gmsh.pdf 但咋就说&a…

【Linux】基础I/O -> 如何谈文件与文件系统?

文件的基础理解 空文件也要在磁盘上占据空间。文件 文件内容文件属性。文件操作 对内容的操作 对属性的操作或者是对内容和属性的操作。标定一个文件&#xff0c;必须使用&#xff1a;文件路径 文件名&#xff08;具有唯一性&#xff09;。如果没有指明对应的文件路径&…

python+reportlab创建PDF文件

目录 字体导入 画布写入 创建画布对象 写入文本内容 写入图片内容 新增页 画线 表格 保存 模板写入 创建模板对象 段落及样式 表格及样式 画框 图片 页眉页脚 添加图形 构建pdf文件 reportlab库支持创建包含文本、图像、图形和表格的复杂PDF文档。 安装&…

软件项目需求分析的实践探索(1)

一、项目启动与规划 组建团队 包括项目经理、系统分析师、业务分析师以及可能涉及的最终用户代表和领域专家等。例如&#xff0c;开发一个医疗管理软件&#xff0c;就需要有医疗行业的专家参与&#xff0c;确保对医疗业务流程有深入理解。明确各成员的职责&#xff0c;如系统分…

Windows下ESP32-IDF开发环境搭建

Windows下ESP32-IDF开发环境搭建 文章目录 Windows下ESP32-IDF开发环境搭建一、软件安装二、搭建IDF开发环境2.1 安装VS Code插件&#xff1a;2.2 配置ESP-IDF插件&#xff1a;2.3 下载例程源码&#xff1a; 三、编译和烧录代码四、Windows下使用命令行编译和烧录程序4.1 配置环…

从 GitLab.com 到 JihuLab.com 的迁移指南

本文分享从 GitLab.com 到 JihuLab.com 的迁移指南。 近期&#xff0c;GitLab Inc. 针对其 SaaS 产品做了限制&#xff0c;如果被判定为国内用户&#xff0c;则会建议使用其在国内的发布版本极狐GitLab。从 GitLab SaaS 产品&#xff08;GitLab.com&#xff09;迁移到极狐GitL…

Mysql-索引的数据结构

为什么要使用索引 索引是存储引擎用于快速找到数据记录的一种数据结构&#xff0c;就好比一本教科书的目录部分&#xff0c;通过目录中找到对应文章的页码&#xff0c;便可快速定位到需要的文章。MySQL中也是一样的道理&#xff0c;进行数据查找时&#xff0c;首先查看查询条件…

ReactPress 1.6.0:重塑博客体验,引领内容创新

ReactPress 是一个基于Next.js的博客&CMS系统&#xff0c; Github项目地址&#xff1a;https://github.com/fecommunity/reactpress 欢迎Star。 体验地址&#xff1a;http://blog.gaoredu.com/ 今天&#xff0c;我们自豪地宣布ReactPress 1.6.0版本的正式发布&#xff0c;…

秒鲨后端之MyBatis【1】环境的搭建和核心配置文件详解

​ 别忘了请点个赞收藏关注支持一下博主喵&#xff01;&#xff01;&#xff01;! ! ! Mybatis简介 MyBatis历史 MyBatis最初是Apache的一个开源项目iBatis, 2010年6月这个项目由Apache Software Foundation迁移到了Google Code。随着开发团队转投Google Code旗下&#xff…

【Go】Go数据类型详解—map

1. 前言 本篇博客将会介绍Go语言当中的另一大核心数据类型——map&#xff08;映射&#xff09;&#xff0c;当然在介绍这个数据类型之前我们还是要思考引入这个数据类型的原因&#xff1a; ❓ 需求&#xff1a;要求完成对一个班级所有同学的信息管理&#xff08;包括但不限于…

Agent 案例分析:金融场景中的智能体-蚂蚁金服案例(10/30)

Agent 案例分析&#xff1a;金融场景中的智能体 —蚂蚁金服案例 一、引言 在当今数字化时代&#xff0c;金融行业正经历着深刻的变革。随着人工智能技术的飞速发展&#xff0c;智能体&#xff08;Agent&#xff09;在金融场景中的应用越来越广泛。蚂蚁金服作为金融科技领域的…

十五、新一代大模型推理架构Mamba

Mamba架构:下一代大模型架构的可能性? 随着深度学习的快速发展,Transformer 架构在过去几年中成为了自然语言处理(NLP)和生成式AI模型的主流架构。然而,Transformer并非完美,其计算效率、长序列建模能力等方面依然存在瓶颈。近期出现的Mamba架构被认为是对这些问题的潜…

LabVIEW中什么和C 语言指针类似?

在LabVIEW中&#xff0c;与C语言指针类似的概念是 引用 (Reference)。 引用在LabVIEW中主要用于以下几个方面&#xff1a; 数据引用&#xff1a;LabVIEW通过引用传递数据&#xff0c;而不是复制数据。通过引用&#xff0c;多个VIs可以共享数据而不需要复制整个数据结构&#xf…

前端编程图表化助手!Echarts入门

Echarts-一个基于javaScript的开源可视化图表库 在日常编程中&#xff0c;我们经常会用到类似饼图、柱状图等&#xff0c;而在网页中使用原生html和css很难做到类似效果。那么作为前端工程师&#xff0c;我们如何做出来一份好看而且实用的图标呢&#xff1f; 那么接下来&…

企业AI助理背后的技术架构:从数据到智能决策

在当今数字化时代&#xff0c;企业AI助理已经成为推动企业数字化转型和智能化升级的重要工具。它们通过整合企业内外部数据资源&#xff0c;运用先进的算法和模型&#xff0c;为企业提供高效、精准的智能决策支持。本文将深入探讨企业AI助理背后的技术架构&#xff0c;从数据收…

Node.js 工具:在 Windows 11 中配置 Node.js 的详细步骤

一、概述 记录时间 [2024-12-25] 本文讲述如何在 Windows 11 中进行 Node.js 工具的安装和配置。 以下是详细的步骤和说明。 二、安装 Node.js 1. 官网下载 通过官网&#xff0c;下载 Node.js&#xff0c;上面有好几种下载方式&#xff0c;文中下载的是 zip 压缩包。 如图&…

【Rabbitmq篇】高级特性----TTL,死信队列,延迟队列

目录 一.TTL 1.设置消息的TTL 2.设置队列的TTL 3.俩者区别 二.死信队列 定义&#xff1a; 消息成为死信的原因&#xff1a; 1.消息被拒绝&#xff08;basic.reject 或 basic.nack&#xff09; 2.消息过期&#xff08;TTL&#xff09; 3.队列达到最大长度 ​编辑 …

Solon v3.0.5 发布!(Spring 可以退休了吗?)

Solon 框架&#xff01; 新一代&#xff0c;面向全场景的 Java 应用开发框架。从零开始构建&#xff08;非 java-ee 架构&#xff09;&#xff0c;有灵活的接口规范与开放生态。 追求&#xff1a; 更快、更小、更简单提倡&#xff1a; 克制、高效、开放、生态 有什么特点&am…