模块和类处理(动态链接)

Module and classes handling (dynamic linking)

本文关键字:动态 链接 处理 模块      更新时间:2023-10-16

遇到一点问题,我正在寻找最好的解决方案概念/理论。

我有一个系统需要使用对象。系统使用的每个对象都有一个已知的接口,可能作为抽象类实现。这些接口在构建时是已知的,并且不会更改。要使用的确切实现将有所不同,我不知道提前什么模块将提供它。唯一的保证是他们会提供接口。类名和模块(DLL)来自配置文件或可以通过编程方式更改。

现在,我已经使用一个相对简单的系统设置了所有这些,设置如下(重写伪代码,只是为了显示基本内容):
struct ClassID
{
    Module * module;
    int number;
};
class Module
{
    HMODULE module;
    function<void * (int)> * createfunc;
    static Module * Load(String filename);
    IObject * CreateClass(int number)
    {
        return createfunc(number);
    }
};
class ModuleManager
{
    bool LoadModule(String filename);
    IObject * CreateClass(String classname)
    {
        ClassID class = AvailableClasses.find(classname);
        return class.module->CreateObject(class.number);
    }
    vector<Module*> LoadedModules;
    map<String, ClassID> AvailableClasses;
};

模块有一些导出函数来给出它们提供的类的数量和这些类的名称/id,然后存储。所有的类都派生自IObject,它有一个虚析构函数,存储源模块,并有一些方法来获取类的ID,它实现了什么接口等等。

唯一的问题是每个模块必须手动加载到某个地方(在配置文件中列出,目前)。我想避免显式地这样做(在ModuleManager之外,在里面,我并不真正关心它是如何实现的)。

我想有一个类似的系统,而不必处理加载模块,只是创建一个对象,(一旦它全部设置)它神奇地出现。

我相信这在某些方面类似于COM打算做的事情。我简单地研究了一下COM系统,但它似乎是令人难以置信的过度杀伤。我只需要系统中已知的类,不需要系统处理的所有其他特性,只需要实现来自某处的接口。

我的另一个想法是使用注册表并保留所有已知/注册类及其源模块和数字的关键,这样我就可以查找它们,并且会出现Manager::CreateClass发现并神奇地使对象。这似乎是一个可行的解决方案,但我不确定它是否是最佳的,或者我是否在重新发明一些东西。

那么,在所有这些之后,我的问题是:如何处理这个?是否有现有的技术,如果没有,如何最好地设置自己?有没有什么陷阱是我应该注意的?

COM很可能就是你想要的。它是非常广泛的,但你不需要使用所有的功能。例如,您不需要要求参与者注册guid,您可以定义自己的机制来创建接口实例。有许多模板和其他机制可以使创建COM接口变得容易。更重要的是,由于它是一个标准,很容易记录需求。

要记住的一件非常重要的事情是,导入/导出c++对象需要所有参与者使用相同的编译器。如果你认为这对你来说是个问题,那么你应该使用COM。如果你愿意接受这个限制,那么你可以继续做你自己。

我不知道是否有任何技术可以做到这一点。

我确实知道我曾经使用过一个非常类似的系统。我们使用XML文件来描述不同模块提供的各种类。我们等效的ModuleManager将解析xml文件,以根据它们提供的类名和系统配置,在运行时确定为用户创建什么。(请求一个实现接口'I'的对象可以返回任何对象'A', 'B'或'C',这取决于系统的配置方式。)

我们发现的最大问题是系统非常脆弱,有时很难调试/理解。仅仅通读代码,通常几乎不可能看到实例化了哪个具体类。我们还发现维护XML产生了比预期更多的bug和开销。

如果我再次这样做,我将保持通过接口从DLL中公开类的设计模式,但我不会试图构建类的中央注册中心,也不会从IObject等基类派生所有内容。

我会让每个模块负责公开自己的工厂函数来实例化对象。