所以我对OO编程有点新意。德尔福具有属性,旨在成为更优雅的"获取课程数据的方式比 getters / setters (在此处阅读usage of property vs getters/setters in business classes)。
我应该何时直接使用这些字段,何时应该在属性中使用 getters / setters ?我只是在需要操纵数据时才会说,但我不确定。
编辑:
省略一个除了返回字段本身值之外什么都不做的setter是错误的吗?
property Field :integer read FField write FField;
答案 0 :(得分:11)
首先,来自documentation on properties的快速摘要:
属性(如字段)定义对象的属性。但是,虽然字段仅是可以检查和更改其内容的存储位置,但属性将特定操作与读取或修改其数据相关联。属性提供对对象属性的访问的控制,并且它们允许计算属性。
存储和访问的分离确实可以通过使用getter和setter来实现,并且保留属性。这是事实,但你链接的问题源于语言差异:Delphi确实有属性,那里的答案已经解释了为什么要使用它们。两个最明显的原因是(1)更清晰的代码和(2)分配能力。我认为this answer已经相当广泛地处理了它。
此外,在不使用属性的情况下,总是需要getter和setter,而不是使用属性。假设一个setter实现,但没有getter:一个属性可以直接读取该字段。
当您只声明属性的名称及其类型时,Delphi的类完成默认为读取私有字段和设置私有字段的私有setter。请注意,这只是默认配置,您可以再次根据需要进行修改。当您完全指定属性声明时,类完成将符合并添加声明所需的私有字段,getter和/或setter。
省略一个除了返回字段本身值之外什么都不做的setter是错误的吗?
当一个属性没有getter或setter并且它只是读取和写入字段时,你可以得出结论,除了一致之外没有区别。但事实并非如此。该字段和属性具有不同的名称,因此可能具有不同的含义。意思是你可以给。请参阅Using properties instead of fields in class methods of the same unit is a bad practice?。
......我只是在需要操纵数据时才会发现......
嗯,这是部分正确的。操纵是众多原因之一。考虑Price
类型的String
属性及其私有字段FPrice
:
FPrice
属于另一个字段时,或者当其他字段超出此类的责任时,请注意,Price
属性非常简陋。离开它的二传手或吸气剂以便将来实施是非常有可能的。但想象一下更高级的属性,这些属性离不开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;
图像控件,专门用于查看您自己的图像格式。 FileName
属性的分配包括:检查正确的文件扩展名,检查文件存在,将文件名存储在私有字段中,加载文件,调整图片的维度,或者撤消先前的分配:
procedure TAwDxfImage.SetFileName(const Value: TFileName);
begin
if FFileName <> Value then
if SameText(ExtractFileExt(Value), '.' + SDxf) and
FileExists(Value) then
begin
FFileName := Value;
FGraphic.LoadFromFile(FFileName);
FGraphic.SetBounds(Width, Height);
end
else
begin
FFileName := '';
FGraphic.Clear;
end;
end;
<子> Source: NLDelphi 子>
答案 1 :(得分:3)
除了@NGLN
回答之外,还有另一个属性getter / setter的用例。
只能通过实例方法访问通过接口访问类实例。如果你必须在这种情况下访问属性,你必须实现getter / setter方法。
type
IField = interface
function GetField: integer;
function SetField(value: integer);
property Field: integer read GetField write SetField;
end;
TField = class(TInterfacedObject, IField)
protected
FField: integer;
function GetField: integer;
function 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
,尽管它被声明为受保护(甚至是私有)。
答案 2 :(得分:1)
不可接受的是这样做
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;
但事实上它是无害的。
这有帮助吗?
这是使用setter
的正当理由或动机procedure TMyClass.SetFu(Value : Integer);
begin
if FFu <> Value then begin
FFu := Value;
if Assigned(FAfterFooChanged) then
FAfterFooChanged(FFu);
end;
end;
不是&#39;操纵&#39;就这样......