在业务类中使用属性和getter/setter的区别

16

在处理像典型的客户(Customer)和员工(Employee)这样的业务类时,是更好地仅使用getter和setter还是使用属性?

我正在翻译一些关于Java书籍中的面向对象示例到Delphi(用于自学)。在这些示例中,总是使用GetName()和SetName(),而不使用属性。

现在,我可以看到,如果我创建一个具有公开属性的组件,那么使用属性将会有非常好的理由,但在普通类中,哪种方法更好呢?是通过使用getter和setter使代码更易读(强调我们正在读取/写入属性),还是使用属性(乍一看可能会与无参数方法混淆)?


5
“Properties”(指Delphi/C#中的属性)实际上就是getter和setter方法,只不过它们已经集成到语言/运行时中。Java没有直接的对应物。 - user166390
3
Delphi中的属性不一定是获取器和设置器。它们可以是获取器和设置器,也可以是直接访问底层字段,如果您不需要任何额外处理的话。 - Mason Wheeler
然而,明智的做法是要记住,直接访问类字段将限制某些面向对象技术的使用。例如,接口中的属性必须通过方法实现,并且多态性(虚拟/抽象属性)需要虚拟getter/setter方法。 - Jørn E. Angeltveit
4个回答

41

哇,属性的含义远不止于“它们只是getter和setter方法的包装器”。

属性是一种优雅而强大的方式,可以提供对类字段的受控访问。

访问字段

正如已经说明的,您可以直接访问类字段。这非常好,并使代码更清晰。这也是实现类的可行第一个版本的一种很好的方式。

TMyClass = class
private
  FValue: String;
public
  property Value: String read FValue write FValue;
end; 

稍后,您可以重新设计您的类以使用方法验证和操作字段访问。公共接口仍然相同。

TMyClass = class
private
  FValue: String;
  procedure SetValue(AValue: String);
public
  property Value: String read FValue write SetValue;
end; 

procedure TMyClass.SetValue(AValue: String);
begin
  if AValue = '' 
  then FValue := 'No value!'
  else FValue := AValue;
end;

控制访问

Properties 可以方便地查看只读/写入字段。例如,一个只读/不可变类:

TClient = class
private
  FName: String;
  FSite: String;
  FMail: String;
public
  constructor Create(AName, ASite, AMail: String);
  property Name: String read FName;
  property Site: String read FSite;
  property Mail: String read FMail;
end; 

多态性

TClient = class
private
  FName: String;
protected
  function GetName: String; virtual; abstract;
public
  property Name: String read GetName write FName;
end; 

TImportantClient = class(TClient)
protected
  function GetName: String; override;
end; 

TArgumentativeClient = class(TClient)
protected
  function GetName: String; override; 
end; 

function TImportantClient.GetName: String; 
begin
  Result := '+++ ' + FName;
end; 

function TArgumentativeClient.GetName: String; 
begin
  Result := ':-( ' + FName;
end; 

{----- ----- ----- ----- -----}
var
  ClientA,
  ClientB: TClient;
begin
  ClientA := TImportantClient.Create;
  ClientB := TArgumentativeClient.Create;

  ClientA.Name := 'Mr. Nice';
  ClientB.Name := 'Mr. Dumbhead';

  ShowMessage(ClientA.Name);
  ShowMessage(ClientB.Name);
end;
{----- ----- ----- ----- -----}

默认属性

在你的类中,你可以定义默认类字段,这意味着你可以直接访问该字段而无需指定属性名。

A := MyStringList[i]:
MyStringList[i] := B;

{ instead of }

A := MyStringList.Strings[i];
MyStringList.Strings[i] := B;

{ or }

A := MyStringList.GetString(i);
MyStringList.SetString(i, B);

索引

使用 Index 关键字,Delphi 将会将一个常量值作为参数传递给 getter/setter 方法。

TMyRect = class
private
  FValues: Array[0..3] of Integer;
  function GetProperty(Index: Integer): Integer;
public
  property Top    : Integer  Index 0  read GetProperty;
  property Left   : Integer  Index 1  read GetProperty;
  property Width  : Integer  Index 2  read GetProperty;
  property Height : Integer  Index 3  read GetProperty;
end;


function TMyRect.GetProperty(Index: Integer): Integer;
begin
  Result := FValues[Index];
end; 

一些资源

还有一些主题需要涵盖(例如实现接口、存储值、RTTI / 设计时属性等),但这篇文章开始变得有点长了...

这些网站上可以阅读更多信息:


2
属性有很多更深入的东西 - 毫无疑问。 - Wolf

14

不需要。在Java中,只有因为它没有属性才需要Getters和Setters。使用属性可以使代码更加清晰简洁。如果需要Getter或Setter,则可以将其构建到属性中,而无需在访问代码中添加大量的函数调用。


所有答案都是正确的,无论如何我会选择一个来告诉大家问题已经得到解答。 - UnDiUdin
1
一个问题:在类中,我可以读/写私有字段或公共属性。是否有一些指南总是在类内部使用字段?因为如果没有规定,有时人们会写字段,有时是属性,这样属性就成为了一个令人困惑的工具。你可能会在同一个类中看到 FName := 'Test' 和 Name := 'Test'。 - UnDiUdin
这取决于您是否还想触发Name属性的任何setter。Setter可能会触发事件等,这些事件可能是您想要启动的,也可能不是。 - Dan Bartlett
1
正如其他人所说,属性是一种非常有价值的资源,远不止于语法糖,因为它提供了简洁、清晰、优雅和受控访问。但是需要注意的是,要仔细观察属性的任何getter或setter是否具有任何副作用。这样的隐藏语义可能会使您的类变得非常难以使用。在属性中产生的副作用比在普通的getter/setter函数中更难理解和最终纠正。 - PA.

10

属性是Delphi的一个很好的优势。我自己做了不少Java和Delphi,毫无疑问会选择属性。实际上,这两种方法最终都会做同样的事情,唯一的区别就在于属性看起来比getter/setter整洁得多。

我建议您选择属性,并充分利用它们!


4
这确实是一种口味和使用的问题。
对于像Pascal程序员这样的人来说,如果你正在读取或写入一个值,那就非常清楚了。因此,如果你不使用Java式的Getter和Setter,而是直接写出你要读取/写入的属性名称,那么代码会更易读。对我来说,我认为对大多数Pascal程序员来说,这样做的代码更易读,我们都知道会调用Getter或Setter方法(如果必要)。
此外,我认为Delphi属性模型的一个巨大优势(和优雅之处)在于你可以直接从字段中获取/设置属性值。如果有很多只有一行代码的Get/Set方法,只是从字段中赋值或读取,那肯定是浪费时间/精力的。

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