保持模块独立,同时仍相互使用 P>我的C++应用程序的大部分使用类来描述数据模型,例如CasStpe(实际上是在C++中模拟反射)。

保持模块独立,同时仍相互使用 P>我的C++应用程序的大部分使用类来描述数据模型,例如CasStpe(实际上是在C++中模拟反射)。,c++,language-agnostic,oop,modularity,C++,Language Agnostic,Oop,Modularity,我想在我的应用程序中添加一个新模块,它需要利用这些类类型,但我不想从我的新模块中引入对类类型的依赖关系 到目前为止,我有以下几种选择: 不使其独立并引入对类类型的依赖,有可能在我的应用程序中创建更多的“意大利面”依赖(这是我最不喜欢的解决方案) 引入一个新类,例如IType,让我的模块只依赖于IType。然后类类型应该继承自IType 使用字符串作为标识方法,并强制新模块的用户将类类型转换为字符串,或者在需要时将其转换为字符串 使用GUID(甚至简单整数)作为标识,还需要在GUID和类类型之间

我想在我的应用程序中添加一个新模块,它需要利用这些类类型,但我不想从我的新模块中引入对类类型的依赖关系

到目前为止,我有以下几种选择:

  • 不使其独立并引入对类类型的依赖,有可能在我的应用程序中创建更多的“意大利面”依赖(这是我最不喜欢的解决方案)
  • 引入一个新类,例如IType,让我的模块只依赖于IType。然后类类型应该继承自IType
  • 使用字符串作为标识方法,并强制新模块的用户将类类型转换为字符串,或者在需要时将其转换为字符串
  • 使用GUID(甚至简单整数)作为标识,还需要在GUID和类类型之间进行转换
在分离应用程序中的模块时,您应该尝试走多远

  • 只需引入一个接口,并让所有其他模块依赖该接口?(与上面描述的类型相同)
  • 甚至通过使用其他标识(如字符串或GUID)将其进一步解耦
我担心,如果将其解耦得太远,代码会变得更不稳定,调试也更困难。我在Qt中看到过这样一个例子:信号和插槽使用字符串链接,如果您犯了键入错误,该功能将不起作用,但它仍然可以编译


您应该在多大程度上保持模块解耦?

99%的时间,如果您的设计基于反射,那么您的设计存在重大问题

一般来说

if (x is myclass)
elseif (x is anotherclass)
else
是一个糟糕的设计,因为它忽略了多态性。如果您这样做,则项目
x
违反了Liskov替换原则


此外,鉴于C++已经有RTTI,我不明白为什么你会重新发明轮子。这就是

typeof
dynamic\u cast
的作用。

我将不再考虑您的反映,而只考虑依赖性的想法

解耦合理的解耦。耦合意味着,如果一件事发生变化,那么另一件事也必须发生变化。因此,您的新代码使用的是类类型,如果它的某些方面发生了更改,那么您肯定必须更改新代码-它不能完全解耦。您希望与以下哪项解耦

  • 语义,类类型的作用
  • 接口,你怎么称呼它
  • 实施,如何实施

  • 在我看来,前两个是合理的耦合。但是,实现更改肯定不需要新代码来更改。因此,将代码转换为接口。我们试图保持接口固定,我们倾向于扩展它们而不是更改它们,尽可能保持它们的兼容性。有时,我们使用名称/值对试图使接口可扩展,然后遇到您提到的打字错误。这是灵活性和“类型安全”之间的权衡。

    这是一个哲学问题;这取决于模块的类型和权衡。我想我个人在不同的时间都做过这些,除了GUID到类型的映射,在我看来,GUID到类型的映射没有任何优势,至少字符串是可读的

    我想说的是,考虑到预期的外部使用和代码组织,您需要了解特定模块需要何种级别的解耦,并从中着手。据我所知,您已经找到了所有的概念方法,它们在特定情况下都很有用


    无论如何,这是我的意见。

    完全同意。重新创建RTTI几乎总是暴露出对C++ OOP的根本缺乏理解。我有充分理由使用基于反射的设计,因为我的应用程序有点特殊。使用配置文件,用户可以使用其他类型和属性扩展数据模型。如果没有基于反射的设计,这是不可能实现的,而且C++的RTTI在这方面也没有帮助。如果没有这种灵活性,我完全同意你的看法。不幸的是,在这种情况下,我不能。@帕特里克:如果你使用的类型是动态的,那么无论如何你都不能用C++的类型来实现你的类型系统。最好使用一个类型
    UserType
    ,它可以包含子
    UserType
    s,然后用户可以扩展它。