属性和函数或过程之间的区别

4

我们能这样说吗:

type
  TPerson = class
   private
     pName : string;
   public
     property Name : string read pName write pName;
end;

等于:

 type
  TPerson = class
   private
     pName : string;
   public
     procedure SetName(val: string);
     function GetName:String;
end;

//{... implementing SetName And GetName...}

请解释一下我们何时需要使用"property",何时不需要。谢谢。


3
在 Delphi 中,惯例是在私有字段前使用 F 作为前缀,例如 FName - Uli Gerhardt
2
使用任何你喜欢的方式,或者更方便的方式。 - David Heffernan
1
我个人不会使用 p 作为私有域的名称,因为 P 已经被广泛用作指针类型,例如 PChar。而 F 是最常用的。 - Jerry Dodge
3个回答

13

这一切都与类的设计有关。从技术上讲,你可以在不使用属性的情况下做到所有事情,但代码将不会如此优雅。良好的设计也使类更易于使用,并降低出错的风险。

首先,你在进行比较

TPerson = class
  private
    FName: string;
  public
    property Name: string read FName write FName;
  end;

为了

TPerson = class
  private
    FName: string;
  public
    procedure SetName(const Name: string);
    function GetName: string;
  end;

这种比较并不十分公平。事实上,在第一种情况下,当值被设置(或读取)时,您没有任何机会进行某些操作。因此,更合适的比较应该是将后面的代码与其进行比较。

TPerson = class
  private
    FName: string;
    procedure SetName(const Name: string);
    function GetName: string;
  public
    property Name: string read GetName write SetName;
  end;

例如,如果您编写一个控件,当您更改属性(例如TPerson的“毛衣颜色”)时,通常需要使控件失效(基本上是重新绘制)。例如,
TPerson = class
  private
    FSweaterColor: string;
    procedure SetSweaterColor(const Value: TColor);
  public
    property SweaterColor: TColor read FSweaterColor write SetSweaterColor;
  end;

  ...

  implementation

  procedure TPerson.SetSweaterColor(const Value: TColor);
  begin
    if FSweaterColor <> Value then
    begin
      FSweaterColor := Value;
      Invalidate; // causes a repaint of the control
    end;
  end;

无论如何,属性的作用是什么?基本上,属性的作用是为类创建一个漂亮的接口:对于不关心其实现细节的人来说,使用应该很容易。通过使用属性,您可以实现此目标。事实上,要读取毛衣的当前颜色,只需读取Anna.SweaterColor,要设置它,只需使用Anna.SweaterColor := clRed。你不知道这是否仅仅设置了一个变量或导致了一个过程运行,也不在意。就你而言,TPerson对象只是有一个可读和可设置的名为SweaterColor的属性。
您还可以创建只读(没有write)或只写(没有read)的属性。但无论如何实现属性的readwrite(如果有的话),从类用户的角度看,属性都是相同的。他无需记住使用SetSweaterColorGetSweaterColor(实际上它们是私有的,不可访问),而只需要使用SweaterColor属性。
这也暗示了使用属性的另一个好处。公共和发布的属性对类的用户可见,而私有成员则不可见(例如字段FSweaterColorSetSweaterColor过程)。这很好。因为现在您知道类用户更改人的毛衣颜色的唯一方法是使用SweaterColor属性,它保证会重新绘制控件。如果FSweaterColor变量是公共的,则类的用户可能设置此变量并想知道“当我更改毛衣颜色时为什么没有发生任何事情?”当然,您不需要属性来获得此好处:私有的FSweaterColor字段和公共的GetSweaterColorSetSweaterColor同样适用,但是那样你需要编写一个GetSweaterColor函数,即使不需要处理也是如此。此外,类的用户需要学习使用两个标识符而不是一个。
更具体地说,如果您使用Delphi IDE进行编程,则会发现published property (-y+ies)将显示在对象检查器中,在那里您可以读取/更改它们(如果适用)。如果没有属性,这怎么可能呢?
所有这些都说了,有时候即使你可以使用属性,你也不会使用。例如,如果你有一个只读的“属性”,你可能会选择一个单一的公共GetSomething函数,而不是一个只读属性。毕竟,这会节省一些编码工作。同样,如果你有一个只写属性,你可以使用一个单一的公共SetSomething过程,这也将节省你的代码。最后,如果你有一个既可读又可写的属性,而且两种方式都不需要处理,那么你可以简单地使用一个公共变量!
因此,归根结底,你需要根据每个类的情况来决定一个良好的设计。我想我的过于冗长的答案的简短版本与David的评论类似:
使用任何你喜欢的,任何更方便的方法。

1
这太片面了。Anna.SweaterColor := clRed 和 Anna.SetSweaterColor(clRed) 之间真的没有太大的区别,只是不同的语法。如果你习惯于后者,那么它读起来就很好。使用它没有问题。唯一重要的区别是能够在属性读取器中返回字段,而不必编写 getter 函数。还有 OI 需要属性。我相信它们是为了服务 OI 而发明的。 - David Heffernan
1
@David:我知道。事实上,我在打扫公寓的时候一直在思考这个问题,已经有十分钟了。我会再添加一些内容。 - Andreas Rejbrand
C++程序员会说,为什么要发明一种语言特性来做我们已经可以很好地完成的事情。我个人认为属性易读,但这有多少是内在的,多少是学习行为呢? - David Heffernan

1

属性是一种很好的语法糖。它们相当于一对getEnabled和setEnabled方法,但大多数程序员(和编程语言)更喜欢使用属性。例如,在代码补全窗口中的条目较少。

此外,它们将“类似变量”的东西(因此数据,对象应该使用的数据)与处理数据的方法分开。

属性不仅限于组件,它们在其他方面也非常有用。您可以使用属性定义公共接口,然后实现一些验证逻辑。(公共字段不可行)但是对于简单的属性,您只需要两行代码,而对于方法则需要8行。

对于对象检查器更重要的是发布关键字,只有已发布的属性才会显示在OI中。


2
此外,它们将“类似变量”的东西(即数据,对象应该处理的内容)与处理数据的方法分开。getter/setter 方法也是如此。 - David Heffernan
但它们仍然是“方法”。在代码完成中具有方法图标。可以用作回调函数。它们会被聚集在代码完成中(按字母顺序排序),我无法看到它们是只读还是读/写。 - DasKrümelmonster

0

不,这两个代码是不相等的。

当我们将 TPerson 类实现为 Delphi 的对象检查器中可定制的组件时,我们使用 property。例如,看一下 TButton 类。在对象检查器中你可以更改的所有内容(CaptionWidthName 等)都在源代码中用 property 关键字标记。

如果您创建一个将在程序中使用但不作为组件的类,则不使用 property 关键字。


5
一个property是对象的一个属性,你可以关联读取和写入数据的操作。它不仅可以在TComponents中使用,对于隐藏类的实现细节也非常有用。 - LU RD
但是,为什么我们在简单的类(非组件)中不使用“属性”?因为它已经做了我们需要做的事情... - Hamed Kamrava
5
Bogdan:你最后一段话完全是错的。确实,已发布的属性会显示在“对象检查器”中,但那只是一个额外的功能。毕竟,Delphi编程语言可以在记事本中使用,你仍然会使用属性。 Translated: Bogdan表示:你最后一段话完全错误。确实,公开的属性会出现在对象检查器中,但这只是额外的好处。毕竟,即使在记事本中使用Delphi编程语言,你仍然会使用属性。 - Andreas Rejbrand
@Bogdan:不完全是这样。更好的表述应该是“...你仍然可以使用属性。” - Andreas Rejbrand
2
但我必须承认,对象检视器的“额外奖励”不仅仅是一个奖励,正如我第一次猜测的那样,甚至可能是引入“属性”关键字的重要动力。 - Andreas Rejbrand
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接