COM背后的动机



我正在努力学习COM。
我想我或多或少对COM的架构有了基本的了解,
但我觉得我还没有完全理解它背后的动机。

维基百科这样说:

对于编写良好的组件,COM允许重用不了解其内部实现的对象,因为它迫使组件实现者提供与实现分离的定义良好的接口。

我的问题是:当我创建一些.dll文件时,
这个dll的客户端也不暴露于实现,
只暴露于接口、含义、他可以使用的功能及其签名

如果有人能向我解释COM背后的动机是什么,以及它解决了什么问题,我会很高兴。

及其解决的问题。

当然。这可能比你要求的要多,但这是我想写一篇博客文章一段时间的话题。

组件对象模式COM有一些好处,但它也因多年的边缘文档、实现的复杂性和开发人员的沮丧而受到了不好的评价。

COM本质上是一组设计模式:

  • 在其核心,它鼓励通过接口进行设计(仅限具有纯虚拟方法的C++类)。

  • 引用计数。当引用计数在当时被引入C/C++开发人员时,这类似于古罗马人被告知数字为零。

  • 鼓励松耦合

  • 这是工厂模式的实现。

  • 它可以用作本地和远程的面向对象抽象过程调用(又称"进程外COM"one_answers"DCOM")

  • 显式链接的位置透明度。应用程序不一定需要知道";其中";磁盘上有一个特定的代码模块(DLL),以便从中实例化对象

  • 执行和语言透明度。COM对象的调用代码和该对象的实现不需要用相同的语言编写。

它能实现什么:

  • 对于本机C++开发,它是实例化DLL中实现的具体C++类的一种非常有效的方法,但它作为纯虚拟方法的抽象基类返回。它使您(开发人员)能够在代码中使用DLL中的C++类,而不必包含一堆混乱的特定于实现的头文件。我可以给你一个简单的头文件,它不显示我的类和COM指南的任何成员变量。然后你只需要用类id和接口id调用CoCreateInstance。我也可以完全重写DLL,它是完全不同的类的具体实现——但只要我公开相同的接口,它就不会破坏你的使用。

  • 不同的跨语言场景。托管C#代码调用本机C++代码。或者将对象投影到脚本语言环境中的本机代码。

  • 插件模型。假设你的应用程序是照片渲染器,你想支持第三方代码,以便能够与你的应用集成,在工具栏上添加一个按钮,并拥有进行一些图像处理的代码。通过标准化如下接口:

    class ImageProcessor : public IUnknown
    {
    public:
    void ApplyEffect(BitmapData* pBitmap) = 0;
    };
    

    供应商只需要提供用COM(注册表项)注册的新DLL,并在应用程序中注册其COM类guid。

  • 一种在进程(本地过程调用)之间进行跨进程通信(在C++中)的合理方法。

  • 微软在允许高级语言(C#和Javascript)使用用低级语言(C++)编写的COM对象方面做得很好。

难以使用的地方:

  • GUID+注册表是一个设计错误。(我说,来吧,兄弟!)。

  • 进程外COM调用本来应该是一种异步调用模式,但COM默认使其同步。

  • 将COM对象注册添加到应用程序设置中是一件苦差事。

  • 微软的IDL文件格式是非标准的,MIDL工具使用起来并不有趣,文档也很简洁。

  • "编组;以及代理/存根DLL。这通常是一本书的一整章。如今,有一些标准的整理人员可以帮助消除混乱。

  • 从DLL中导出一个基本的C++对象需要大量的开销。在某些情况下,使用基于IUnkown的实现更容易,但只需从DLL中导出自己的工厂函数,而不是通过CoCreateInstance加载它。ATL模板类使这更容易。

  • 进程外的线程模型。我在这儿骑墙。他们再也找不到比";公寓;在COM中引入线程模型。大多数书籍在解释STA和MTA之间的差异时都做得很糟糕。但一旦你了解了其中的差异,读够了陈的博客文章,你就会真正欣赏它,并知道如何使用它进行设计。我只花了20年的时间就明白了这一点。

  • 进程外COM调用泵窗口消息,并在应用程序中引入意想不到的随机错误。这就是为什么进程内与进程外COM对象之间的位置透明性有些神话的原因之一。

最新更新