|
|
1
24
理解这一点的关键是认识到这不仅仅是 定义 与 实施 . 这是关于描述同一个名词的不同方式:
假设你在做一个厨房的模型。(为下面的食物类比道歉,我刚从午餐回来…)你有三种基本的餐具-叉子、刀和汤匙。这些都适合 器具 类别,因此我们将对其建模(我省略了一些无聊的东西,如支持字段):
所有这些都描述了任何工具所共有的数据和功能——它是由什么组成的,它的重量(取决于具体类型)等等,但是您会注意到抽象类实际上并不
做
什么都行。一
好吧,我们可以开始扩展层次结构,但它会变得混乱:
这需要处理尖锐的问题,但是如果我们想以这种方式分组呢?
当然,这方面的真正问题是,我们使用继承来描述对象 做 不是什么 是 . 对于前者,我们有接口。我们可以清理这个设计很多:
现在我们可以理清具体类型的作用:
我想每个人都知道这个主意。要点(没有双关语)是我们对整个过程有非常精细的控制,并且我们不需要做任何权衡。我们都在利用遗产 和 这里的接口,选择不是相互排斥的,只是我们只包含抽象类中的功能,这是真正的 常见的 到所有派生类型。 您是否选择使用抽象类或下游的一个或多个接口,实际上取决于您需要如何处理它:
这是有道理的,因为只有餐具可以放在洗碗机里,至少在我们有限的厨房里是这样,那里不包括诸如盘子或杯子之类的奢侈品。这个
另一方面:
这可能不太好。他不能只吃
这更有意义:
现在我们可以给他
您还将注意到第二个版本对类层次结构中的更改不太敏感。如果我们决定改变
我也对这里的引用计数问题有所掩饰,我认为@deltics说得最好,只是因为你有这个问题。
事实上,我会这么说的
大多数时候,您可能不希望引用计数语义
. 是的,我说了。我一直觉得整个引用计数只是为了帮助支持OLE自动化等等。(
所以这个故事的寓意是:
|
|
|
2
8
我怀疑这是一个“更好的方法”的问题——他们只是 不同的用例 .
|
|
|
3
5
您可以有没有引用计数的接口。编译器为所有接口添加对addref和release的调用,但这些对象的生命周期管理方面完全取决于iunknown的实现。 如果您从TinterfacedObject派生,则对象生存期确实将被引用计数,但是如果您从Tobject派生自己的类并实现IUnknown,而不实际计算引用,也不在实现Release时释放“self”,则您将得到一个支持接口但具有显式管理的Lifeti的基类。我是正常的。 由于编译器自动生成了对addRef()和release()的调用,因此仍然需要小心处理这些接口引用,但这与小心处理常规tobject的“悬空引用”没有太大区别。 这是我过去在复杂和大型项目中成功使用的东西,甚至混合了支持接口的引用计数对象和非引用计数对象。 |
|
|
4
3
在Delphi中,有三种方法可以将定义与实现分离。
3: -如果您从TinterfacedObject派生,引用计数实际上会考虑对象的生命周期,但这不是真实性。 -例如,tcomponent也实现了IInterface,但没有引用计数。这会带来一个大警告:在销毁对象之前,请确保您的接口引用设置为nil。Comiler仍将向您的接口插入递减调用,该调用看起来仍然有效,但不有效。第二:人们不会期望这种行为。 在2和3之间选择有时是非常主观的。我倾向于使用以下方法:
|
|
|
5
1
在我处理超大项目的经验中,这两个模型不仅工作得很好,甚至可以毫无问题地共存。与类继承相比,接口的优势在于,您可以将特定的接口添加到不从公共祖先继承的多个类中,或者至少在不将代码引入层次结构的情况下,可能会在已经证明有效的代码中引入新的错误。 |
|
6
1
我不喜欢使用COM接口,除非有人已经制作了一个。也许这是因为我对COM和类型库的不信任。我甚至把接口“伪造”成带有回调插件的类,而不是使用接口。我想知道是否有其他人感受到了我的痛苦,并且避免了像瘟疫一样使用界面? 我知道有些人会认为我对界面的回避是一个弱点。但是我认为所有使用接口的Delphi代码都有一种“代码味道”。 我喜欢使用委托和任何其他我能使用的机制,将我的代码划分为多个部分,并尝试尽我所能地使用类,永远不要使用接口。我不是说这很好,我只是说我有我的理由,我有一个规则(有时可能是错误的,对某些人来说总是错误的):我避免接口。 |