【问题标题】:Reference counted TList<T> vs TObjectList<T>引用计数 TList<T> 与 TObjectList<T>
【发布时间】:2018-03-05 21:25:18
【问题描述】:

谁能指出在 TList 中使用对象接口的教程或最佳实践?

我开始实施此模型以利用引用计数作为 TObjectList(我广泛使用)的替代方法。虽然我在实现列表时没有遇到任何问题,但这样做似乎会以其他方式增加复杂性。

特别是因为列表只包含一个接口,我无权访问类字段(很明显)。所以我最终用“MyInterface as TMyClass”乱扔代码,或者创建了很多函数来访问这些字段。是否有一些我不知道的技巧可以使界面容器更有用?

【问题讨论】:

  • 扩展您的界面以支持您需要的一切。或者,如果您不想这样做,并且通常有很好的理由不这样做,请使用类。
  • 如果你非得写MyInterface as TMyClass,你会觉得你打破了接口的抽象原则,也打破了大部分的SOLID原则。并且将接口放入列表通常也是不安全的,因为它打开了接口循环引用的大门,从而导致实例泄漏。

标签: delphi generics containers


【解决方案1】:

如果您需要访问某些方法,为什么要用接口隐藏它们?接口就是这样:描述其他人可以与该对象进行交互的方式 [interface]:如果您希望其他类作为接口对象与您的类进行交互,那么这些方法应该是界面。

使用接口作为简化终结的快捷方式,然后通过强制转换来破解它违反了接口的整个概念,并且还可能导致内存泄漏和难以追踪 AV,因为您混合引用的方式:有时是接口,有时是 TObject。

谁能指出我使用对象的教程或最佳实践 TList 中的接口?

您的问题与 TList 无关。 TList 所做的只是保存对对象的引用,无论它们是如何设计的——它对对象接口或实现的细节一无所知。正如@ArnaudBouchez 在 cmets 中指出的那样,您的问题是您没有正确设计类和接口。


我开始实施此模型以利用参考 计数作为 TObjectList 的替代品(我广泛使用)

为什么有必要这样做?为了简化定稿? TObjectList 默认拥有它的对象。 (您还可以设置OwnsObjects 属性)。如果您使用 TObjectList,则不需要使用接口来自动进行清理。您只需释放 TObjectList 实例,就像您必须释放 TList 一样。除非您出于特定原因需要接口,否则使用 Objects 和 TObjectList 可以说是更可取的,因为与接口相反,您的最终确定是确定性的。

来自 XE 帮助:

创建 TObjectList 实例。

此重载方法创建一个 TObjectList 实例。

OwnsObjects 参数是一个布尔值,表示对象是否 条目归列表所有。如果对象是拥有的,当条目 从列表中删除,对象被释放。拥有对象 属性是从此参数的值设置的。默认为真。

当你释放 TObjectList 时,OwnObjects=True 时对象也会被释放。
请参阅: Clear a TList or a TObjectList (accepted answer there)

知道:通常情况下,作为 Delphi 开发人员,您完全没有理由涉足引用计数的细节。如果你觉得你需要这样做,那么你的设计在基本层面上是有问题的。引用计数在 TInterfacedObject 中实现,并且透明地工作。您的所有 Delphi 接口对象都应派生自 TInterfacedObject(或其同级或派生类之一),如下所示:

interface
...

type

IMyInterface=interface (IUnknown)
[GUID]
 function GetValue:integer;
end;

TMyInterface=class(TInterfacedObject,IMyInterface)
 protected
   function GetValue:integer;
end;

implementation
...


TMyInterface.GetValue:integer;
begin
  result := fValue;
end;

end.

然后像这样使用它:

procedure useValue;
var im:IMyInterface;
    x:integer;
begin
 im:=TMyInterface.create;
 x:=im.GetValue;
 showMessage(inttstr(x));
end;

当useValue 返回时,im 将被清理——您无需执行任何操作或担心引用计数。 TInterfacedObject 负责所有这些。


请注意,在 useValue 中,您将引用声明为 IMyInterface,但调用 TMyInterface 的类构造函数 - 这就是您必须初始化接口的方式 - 接口没有构造函数。但是,由于您的引用类型是 IMyInterface,编译器就是这样处理它的 - 只有通过 IMyInterface 公开的方法才能访问。

【讨论】:

  • 您说得对,我认为接口的引用计数功能可以更轻松地管理对象,但您所说的完全有道理。我试图让自己更多地使用接口(因为它似乎是推荐的做法)作为一个老 OO 开发人员很难学习新技巧。我也对 [weak] 接口指针非常感兴趣,它可以作为对列表中项目的引用的一种方式,当项目被删除时,它会自动为空,但反思一下,对它的需求可能是我的糟糕设计。
  • 我正在努力让自己更多地使用接口(因为它似乎是推荐的做法 - 不要仅仅因为它的“推荐做法”而做某事 - 这样做是因为你有一个可以更好地解决的问题,或者在使用“推荐实践”时可以实现的改进。接口对某些事情有好处,但并非总是如此。ObjectLists、受保护的单例和类方法通常是更好的解决方案。使用类方法和一种函数式编程方法,您可能会发现 50% 的对象根本不需要初始化。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-11-26
相关资源
最近更新 更多