Class Delphi类:属性与Get/Set方法

Class Delphi类:属性与Get/Set方法,class,delphi,properties,setter,getter,Class,Delphi,Properties,Setter,Getter,所以我对OO编程有点陌生。Delphi有属性,它是一种比getter/setter更“优雅”的访问类数据的方法(请在此处阅读) 什么时候应该直接使用字段,什么时候应该在属性内部使用getter/setter?我只是在数据需要处理的时候才使用gessing,但我不确定 编辑: 省略只返回字段本身值的setter是否错误 property Field :integer read FField write FField; 为什么是房地产? 对于初学者,下面是以下内容的简要总结: 属性(如字段)定

所以我对OO编程有点陌生。Delphi有属性,它是一种比getter/setter更“优雅”的访问类数据的方法(请在此处阅读)

什么时候应该直接使用字段,什么时候应该在属性内部使用getter/setter?我只是在数据需要处理的时候才使用gessing,但我不确定

编辑:

省略只返回字段本身值的setter是否错误

  property Field :integer read FField write FField;
为什么是房地产? 对于初学者,下面是以下内容的简要总结:

属性(如字段)定义对象的属性。但是,虽然字段只是一个存储位置,其内容可以检查和更改,但属性将特定操作与读取或修改其数据相关联。属性提供对对象属性访问的控制,并允许计算属性

为什么不仅仅是塞特和盖特? 存储和访问的分离确实可以通过只使用getter和setter来实现,而不使用属性。这是真的,但是您链接到的问题源于语言的差异:Delphi确实有属性,并且那里的答案已经解释了为什么要使用它们。两个最明显的原因是(1)更干净的代码和(2)分配能力。我认为这方面的工作已经相当广泛了

此外,在不使用属性的情况下,始终需要getter和setter,而使用属性则不需要getter和setter。假设是setter实现,但没有getter:属性可以直接读取字段

结业 当您仅声明属性的名称及其类型时,Delphi的类完成默认为读取私有字段和设置私有字段的私有setter。请注意,这只是默认配置,您可以根据需要再次修改它。当您完全指定属性声明时,类完成将符合要求,并根据您的声明添加一个私有字段、一个getter和/或setter

不带getter和setter的属性 省略只返回字段本身值的setter是否错误

当一个属性既没有getter也没有setter,它只读取和写入字段时,您可以得出结论,除了保持一致性之外,没有什么区别。但事实并非如此。字段和属性具有不同的名称,因此可能具有不同的含义。意思是你可以给予。看

何时使用getter或setter? 。。。我只是在数据需要处理的时候才这么说

嗯,这在一定程度上是正确的。操纵是众多原因之一。考虑<代码>价格>代码>属性<代码>字符串< /代码>,其私有字段<代码> f价格< /C> >:

  • 限制:当价格需要等于或高于零时
  • 委托:当
    FPrice
    是另一个字段的一部分时,或者当它超出了此类的责任范围时
  • 验证:当价格在逗号后可能只有两位小数时
  • 解释:当价格以千为单位输入,但应以美分为单位存储时
  • 影响:当价格对其他领域产生影响时,例如费率或保证金
  • 激活:当对价格进行编辑需要立即执行操作时,例如更新GUI
  • 换算:当价格以美元输入,但应以日元存储时
  • 取消:当价格没有意义时,例如在科学记数法中输入价格时
请注意,
Price
属性是非常基本的。将其setter或getter留给将来的实现是很有可能的。但是想象一下,如果没有setter或getter,更高级的属性是无法实现的:

  • 咨询前需要创建的字段:

    function TMyObject.GetBarelyUsed: TRare;
    begin
      if FBarelyUsed = nil then
        FBarelyUsed := TRare.Create(Self);
      Result := FBarelyUsed;
    end;
    
  • 可以选择项目,但项目本身不知道该做什么。相反,所有者会这样做。请注意,在本例中完全没有私有字段:

    procedure TItem.SetSelected(Value: Boolean);
    begin
      if Value <> Selected then
      begin
        if Value then
          Owner.Selection.Add(Self)
        else
          Owner.Selection.Remove(Self);
      end;
    end;
    

这样做是不可接受的

TMyClass = class
private
public
  Fubar :integer;
end;
你剩下的例子很好。我很高兴收到您这样的代码

TMyClass = class
private 
  FFu : integer;
public
  property Fu :integer read FFu write FFu;
end;
因为我可以自信地把它改成

TMyClass = class
private 
  FFu : integer;
  procedure SetFu(Value : Integer);
  function GetBar() : string;
public
  property Fu :integer read FFu write SetFu;
  property Bar : String read GetBar;
end;
在不破坏现有代码的情况下

我个人不喜欢无所事事的二传手

procedure TMyClass.SetFu(Value : Integer);
begin
  FFu := Value;
end;
但事实上,这是无害的

这有用吗

这将是使用二传手的有效理由或激励

procedure TMyClass.SetFu(Value : Integer);
begin
  if FFu <> Value then begin  
    FFu := Value;
    if Assigned(FAfterFooChanged) then
      FAfterFooChanged(FFu);
  end;
end;
过程TMyClass.SetFu(值:整数);
开始
如果是FFu值,则开始
FFu:=数值;
如果已分配(更改),则
fafterfood(FFu);
结束;
结束;

不是这样的“操纵”…

除了
@NGLN
答案之外,还有另一个属性getter/setter用例

只有通过实例方法才能通过接口访问类实例。如果在这种情况下必须访问属性,则必须实现getter/setter方法

type
  IField = interface
    function GetField: integer;
    procedure SetField(value: integer);
    property Field: integer read GetField write SetField;
  end;

  TField = class(TInterfacedObject, IField)
  protected
    FField: integer;
    function GetField: integer;
    procedure SetField(value: integer);
  public
    property Field: integer read GetField write SetField;
  end;

var
  f: IField;
  x, n: integer;
...
  f := TField.Create;
  f.Field := 5;
  f.SetField(6);
  n := f.Field;
  x := f.GetField;
当然,根据您是否只需要对该属性进行读或写访问,您可以在接口声明中省略setter或getter


请记住,通过接口访问实例使所有接口实现的方法都具有公共可见性。这就是为什么在上面的示例中,您可以调用
f.GetField
,尽管它被声明为受保护的(甚至是私有的)。

这里有四个问题,这三个问题太多了。即便如此,许多问题实际上是在征求主观意见。我认为你需要缩小关注点。Thx我会想出一个更好的方式来解决它,一个问题本身就是两个问题。使用setter/getter或只是两者的包装器的属性没有真正的区别。getter/setter方法通常是decl
type
  IField = interface
    function GetField: integer;
    procedure SetField(value: integer);
    property Field: integer read GetField write SetField;
  end;

  TField = class(TInterfacedObject, IField)
  protected
    FField: integer;
    function GetField: integer;
    procedure SetField(value: integer);
  public
    property Field: integer read GetField write SetField;
  end;

var
  f: IField;
  x, n: integer;
...
  f := TField.Create;
  f.Field := 5;
  f.SetField(6);
  n := f.Field;
  x := f.GetField;