使用接口或抽象类分离定义和实现的更好方法是什么?
实际上,我不喜欢将引用计数对象与其他对象混合。我想在保持大项目时这可能成为一场噩梦。
但有时我需要从2个或更多类/接口派生一个类。
你的经历是什么?
答案 0 :(得分:24)
答案 1 :(得分:8)
我怀疑这是一个“更好的方法”的问题 - 他们只是有不同的用例。
如果您没有类层次结构,并且您不想构建一个层次结构,并且将不相关的类强制到同一层次结构中甚至没有意义 - 但是你想要平等对待一些类,而不必知道类的具体名称 - >
接口是可行的方法(例如,考虑Javas 可比较或 Iterateable ,如果您必须从这些类派生(假设它们是class =) ,他们将毫无用处。
答案 2 :(得分:5)
您可以使用没有引用计数的接口。编译器为所有接口添加对AddRef和Release的调用,但这些对象的生命周期管理方面完全取决于IUnknown的实现。
如果从TInterfacedObject派生,对象生存期确实会被引用计数,但是如果从TObject派生自己的类并实现IUnknown而不实际计算引用并且在Release的实现中没有释放“self”那么你将得到一个基础支持接口但具有正常管理生命周期的类。
由于自动生成的对编译器注入的AddRef()和Release()的调用,你仍然需要小心那些接口引用,但这与注意常规TObject的“悬空引用”并没有多大区别。
这是我过去在复杂和大型项目中成功使用的东西,甚至包括支持接口的ref计数和非ref计数对象。
答案 3 :(得分:3)
在Delphi中,有三种方法可以将定义与实现分开。
您可以在每个单元中分隔,您可以将publuc类放在接口部分中,并在实现部分中实现它。代码仍然驻留在同一个单元中,但至少代码的“用户”只需要读取接口而不是实现的内容。
在类中使用虚拟或动态声明的函数时,可以覆盖它们 子类。这是大多数类库使用的方式。看看TStream及它的派生类,如THandleStream,TFileStream等。
当您需要不同于层次派生的层次结构时,可以使用接口。接口总是从IInterface派生而来,它被建模为基于COM的IUnknown:你可以获得引用计数和查询类型信息。
3: - 如果从TInterfacedObject派生,引用计数确实会处理对象的生命周期,但这不是必须的。 - 例如,TComponent也实现了IInterface但没有引用计数。这带有一个大警告:确保在销毁对象之前将接口引用设置为nil。编译器仍然会向你的界面插入递减调用,看起来仍然有效但不是。第二:人们不会期待这种行为。
在2和3之间选择有时是非常主观的。我倾向于使用以下内容:
答案 4 :(得分:1)
根据我对超大型项目的经验,这两种模型不仅运行良好,甚至可以毫无问题地共存。接口具有优于类继承的优点,因为您可以将特定接口添加到不会从共同祖先下降的多个类,或者至少在没有将代码引入到层次结构中的情况下,您可能会冒险在代码中引入新错误已被证明有效。
答案 5 :(得分:1)
我不喜欢COM接口,以至于从来没有使用它们,除非有其他人生产过它。也许这来自我对COM和类型库的不信任。我甚至将“伪造”接口作为具有回调插件的类而不是使用接口。我想知道是否有其他人感受到我的痛苦,并避免使用界面,好像他们是瘟疫?
我知道有些人会认为我避免接口是一个弱点。但我认为所有使用Interfaces的Delphi代码都有一种“代码味道”。
我喜欢使用委托和任何其他机制,将我的代码分成几个部分,并尝试用类做我能做的一切,从不使用接口。我不是说这很好,我只是说我有我的理由,而且我有一个规则(有时可能是错的,有些人总是错的):我避免接口。