2025-03-21-微软的Proxy学习

NS

Posted by 大狗 on January 24, 2025

微软的Proxy学习

这几天看下https://github.com/microsoft/proxy,学习下如何避免使用继承的情况下,高效方便地使用C++多态( polymorphic programming)的方法。先对着README.md看看怎么阅读这个源代码(实际上就是翻译了一下README.md)。

怎么使用Proxy库?这里不展示整个的用法了,只把抽象那块的东西抽出来:

最关健的用法如下所示,简单来说就是需要组合一些行为(表达式expression)构建出来具体的外观模式

  • // 定义一个facade type: Formattable, 
    struct Formattable : pro::facade_builder ... ::build {}
    

    具体的pro::facade_builder请参考https://microsoft.github.io/proxy/docs/ProFacade.html,是Proxy库提供的运行时抽象(这里稍微动一下脑子理解下,代码是compile time的时候制定了runtime满足什么行为)。

    相应的解释请看

  • 让我们再看另一个例子struct Streamable : pro::facade_builder ... ::build {}: 定义一个 Streamable 外观模式,相应的功能为

    • pro::facade_builder: 准备定义另一种外观模式.
    • add_convention: 添加调用约定,调用约定由dispatch和overload构成。这里说起来有一些拗口:什么是dispatch?什么是overload?overload好理解,可以理解为函数签名,就是具体函数的形式。dispatch呢?这里我个人认为就是功能,名字,用法之类的抽象。这里我觉得简单理解为concept就可以了
    • pro::operator_dispatch<"<<", true>: Specifies a dispatch for operator << expressions where the primary operand (proxy) is on the right-hand side (specified by the second template parameter true). Note that polymorphism in the “Proxy” library is defined by expressions rather than member functions, which is different from C++ virtual functions or other OOP languages.
    • std::ostream&(std::ostream& out) const: 调用约定里面的overload,函数签名部分,和std::move_only_function. 一样的。const 指明这个函数是 const的,不会改动对象内部.
    • build: 将上下文构建为具体的facade模式.
  • .

如果不清楚到底什么是facade type,可以参考这个解释:

“Facade” 是一种软件设计模式,通常被称为 “外观模式”。这种设计模式提供了一个更高层次的接口,用于简化复杂系统的使用。Facade 模式的核心思想是为子系统中的一组接口提供一个统一的接口,从而让这个子系统更容易使用。

在软件开发中,Facade 模式的典型特征包括:

  1. 简化接口:通过提供一个简单的接口来隐藏系统的复杂性,从而减少使用者与系统之间的交互复杂度。
  2. 分离代码:将客户端与复杂的类库或 API 分离,使客户端代码更简洁,减少对外部复杂系统的依赖。
  3. 提高可维护性:通过引入 Facade,可以在不影响客户端的情况下更改子系统。
  4. 降低耦合度:客户端与子系统的耦合度降低,因为它们通过 Facade 进行交互,而不是直接依赖子系统的具体实现。

Facade 模式常用于提供简单的接口来处理与库、框架或一组复杂类的交互,是一种结构型设计模式,有助于提高系统的模块化和可维护性。

除了刚才提到的一些,还有一些其他有用的feature

  • 重载:facade_builder::add_convention比上面展示的两个例子功能更强大。它可以接受任意数量的重载类型(严格来说,任何满足ProOverloadhttps://microsoft.github.io/proxy/docs/ProOverload.html要求的类型),在调用proxy时执行对函数执行重载解析。
  • 外观模式组合: facade_builder::add_facade允许不同抽象的灵活组合。
  • 概念:为了便于使用“proxy”进行模板编程,从facade类型中导出了三个概念。即,proxiable、proxiable_target和inplace_proxiable_target。
  • 分配器感知: 函数模板allocate_proxy具备从任何自定义分配器的值创建一个proxy对象的能力。在 C++11 中,std::function和std::packaged_task的构造函数接受指定自定义分配器的功能以进行性能调优,但在 C++17 中这些被移除,因为“语义不明确,并且在未存储类型信息的上下文中,后续复制赋值期间如何再次拿到类型信息的技术问题”。这些问题不适用于allocate_proxy
  • 可配置的约束: facade_builder为约束配置提供全面支持,包括内存布局(通过restrict_layout)、可复制性(通过support_copy)、可重定位性(通过support_relocation)以及可析构性(通过support_destruction)</
  • 反射:proxy支持基于类型的编译时反射,这个反射支持进行运行时查询。有关更多详细信息,请参考facade_builder::add_reflection和函数模板proxy_reflect。
  • 非接管(管理)代理:尽管proxy可以像智能指针一样有效地管理对象的生命周期,但有时我们希望对其进行解引用传递再传递到非接管上下文。3.2.0 版本以来,将这种能力作为扩展实现。有关更多详细信息,请参考函数模板make_proxy_view
  • 运行时类型信息(RTTI):运行时类型信息(RTTI,run-time-type-information)自上世纪以来在 C++中提供了“较弱”的反射能力。虽然它不像其他一些语言中的反射那么强大(例如 C#中的 Object.GetType()或 Java 中的 Object.getClass()),但它在运行时为类型安全地强制类型转换提供了基本的基础设施。自 3.2 版本以来,“针对proxy的运行时类型信息”已作为扩展实现,并允许用户为每个外观模式定义决定是否实现rtti。有关更多详细信息,请参考facade_builder::support_rtti。
  • 共享和弱所有权:虽然proxy可以从std::shared_ptr创建,但自 3.3.0 起的拓展支持用户可以更高效地创建具有共享和弱所有权的proxy对象。更多详细信息请参考函数模板make_proxy_shared、allocate_proxy_shared、别名模板weak_proxy
  • 弱dispatch:当一个对象未实现调用约定,而我们不希望它构建的时候直接触发编译错误导致构建失败时,可以指定一个在调用时抛出异常的weak_dispatch。

结尾

唉,尴尬

狗头的赞赏码.jpg