【问题标题】:which is the best way to control a object-field type life-cycle?控制对象字段类型生命周期的最佳方法是什么?
【发布时间】:2011-09-28 02:58:57
【问题描述】:
TMyClass = class(TObject)
private
  FMyObject: TObject;
  function GetMyObject: TObject;
public
  property MyObject: TObject read GetMyObject write FMyObject;
end;

function TMyClass.GetMyObject: TObject;
begin
  if FMyObject = nil then
    FMyObject := TObject.Create;

  Result := FMyObject;
end;

有时,“MyObject”不是在内部创建,而是在外部创建并分配给参数。如果这个对象是在外部创建的,我不能在这个上下文中释放它。

我应该创建一个 TList 并添加所有内部创建的对象并销毁析构函数上的所有内容吗?

如果参数是在内部创建的,我如何控制它的生命周期?你建议做什么?有什么模式可以做到这一点吗?

【问题讨论】:

  • 如果 MyObject 具有私有访问修饰符,如何在外部创建它?除了这个类没有看到这个属性
  • @heximal:最有可能(不在示例代码中)通过构造函数注入。
  • @heximal:该字段是私有的,该属性是公共的,可读写,即可以像Obj.MyObject := TSomeObject.Create;一样使用。
  • 你是对的,对不起,没有注意到属性声明
  • @ain 在这种情况下,之前由 Getter 创建的 FMyObject 实例引用将不复存在。所以@Eduardo,你的财产应该有一个setter。

标签: delphi oop


【解决方案1】:

我想最好的办法是重新设计你的代码,这样就不会出现这个问题——这种所有权模糊是一团糟。

无论如何,一种选择是使用(引用计数)接口。这在循环引用的情况下是有问题的。

如果外部创建的对象不能是唯一的引用,那么您仍然可以创建对象的内部副本,例如

procedure TMyClass.SetMyObject(const Value: TObject);
begin
   MyObject.Assign(Value);
end;

您可以将外部对象分配给与内部不同的字段,然后在析构函数中不要Free 该字段。或者在属性设置器中设置一个标志,以便您知道不要释放外部对象...

【讨论】:

  • +1 VCL中使用了copy on assignment模式,因此其他Delphi开发人员应该熟悉,增强可维护性。
  • @Nat Copy on assignment 很好,除非你真的想引用一个共享对象。
【解决方案2】:

我会在属性设置器中设置一个标志

procedure TMyClass.SetMyObject(AObject: TObject);
begin
  if Assigned(MyObject) and FIsMyObject then
    FMyObject.Free;
  FIsMyObject := False;
  FMyObject := AObject;
end;

function TMyClass.GetMyObject: TObject;
begin
  if FMyObject = nil then
  begin
    FMyObject := TObject.Create;
    FIsMyObject := True;
  end;

  Result := FMyObject;
end;

Destructor TMyClass.Destroy;
begin
    if FIsMyObject then
        FMyObject.Free;
end;

【讨论】:

  • +1 我总是这样做。感觉有点不雅,但我还没有找到我喜欢的替代品。
【解决方案3】:

已经给出了两个最合乎逻辑和实用的解决方案(保留标志,分配时复制),但是为了完整起见并且由于对象字段不太可能是 TObject 类型,这里有其他三种方法。这些的实用性取决于对象字段的类型,是否真的不想要额外的布尔标志以及是否不喜欢在此构造中添加一些智能行为。

(警告:这可能有点牵强。)

  • 测试对象字段是否属于您的私有对象类型:

        property MyObject: TSomeAncestor read GetMyObject write SetMyObject;
      end;
    
    implementation
    
    type
      TMyObject = class(TSomeAncestor) ... end;
    
    destructor TMyClass.Destroy;
    begin
      if FMyObject is TMyObject then
        FMyObject.Free;
    
  • 测试对象字段的所有权:

        property MyObject: TOwnedObject read GetMyObject write SetMyObject;
      end;
    
    implementation
    
    destructor TMyClass.Destroy;
    begin
      if FMyObject.Owner = Self then
        FMyObject.Free;
    

    如果外部对象无论如何都应该由此类释放,则此构造特别有用:只需将其所有者设置为此类实例。该决定不再取决于对象的内部或外部创建。

  • 如果对象字段来自 TComponent,那么您根本不必释放。

【讨论】:

    猜你喜欢
    • 2012-01-22
    • 2013-06-11
    • 2014-11-20
    • 2013-04-12
    • 2022-01-16
    • 1970-01-01
    • 2018-08-23
    • 2011-08-24
    • 1970-01-01
    相关资源
    最近更新 更多