When dealing with buisness classes, like the typical Customer and Employee classes, is it better to use getters and setters only or to use properties?
I am translating to Delphi (for self learning) some OO examples from java books, in those examples there is always GetName() and SetName(), properties are not used.
Now, I can see that if I create a component with published properties I have a very good reason for using properties, but in normal classes, which approach is better? Is the code More Readable with getters and setters (that emphasize the fact we are reading/writing a property) or with properties (that at first sight can be confused with parameterless methods)?
Wow. There is sooo much more to properties than "they'r just wrappers for the getter and setter methods".
Properties are an elegant, yet powerful, way to provoide controlled access to the class fields.
As already stated, you can access the class fields directly. This is very nice indeed and makes the code clearer. It is also a very nice way to implement a workable first version of your class.
TMyClass = class
private
FValue: String;
public
property Value: String read FValue write FValue;
end;
Later on, you can redesign your class to validate and manipulate the field access using methods. The public interface will is still the same.
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 gives you an easy overview of readonly/writeonly fields. E.g. a readonly/immutable class:
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;
{----- ----- ----- ----- -----}
In your class, you can define a default class fields which means that you can access the field directly without specifying the property name.
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);
With the Index
keyword, Delphi will pass a constant value as an argument to the getter/setter methods.
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;
There are still some topics to cover (implementing interfaces, stored values, RTTI/design time properties etc), but this post started to get a bit long...
More can be read at these sites: