views:

183

answers:

4

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)?

+9  A: 

Properties are a great advantage of Delphi. I have done quite a bit of Java and Delphi myself and definitely would go for Properties. Practically both approaches will eventually do the same thing, with the only difference that properties look MUCH neater than getters/setters.

I suggest you go for properties, and take full advantage of them!

Ed.C
+8  A: 

No. Getters and setters are only there in Java because it doesn't have properties. It makes for much cleaner code to use properties. And then if you need a getter or a setter, you can build it into the property, but you don't have to litter the accessing code with a bunch of function calls.

Mason Wheeler
All answrs are correct, anyway I choose one to tell the question has been answered.
A question: inside a class I can either read/write the private field or the public property. Is there a guideline for always using the field inside the class? Because if no rule is there sometimes people wirtes the fiels, sometimes the property, and in this way properties become a confusing tool. One can see in the same class FName := 'Test' and Name := 'Test'.
It depends whether you want any setter for the Name property to be triggered also. The setter may trigger events etc. which you may or may not want to launch at that time.
Dan Bartlett
As others have already said, properties are a valuable resource well beyond syntactic sugar, as it provides conciseness, clarity, elegance and controlled access.**But** there is a caveat. Carefully watch that any getter or setter of a property does not have any side effects. Such hiden semantics may make your class really difficult to use. Collateral damages are much more dificult to understand and eventually correct in a property than in plain getter setter functions.
PA
+2  A: 

It really is a matter of taste and use.

For pascal like programmers, it's very clear if you're reading or writing a value, so I think the code is more readable if you do not use getters and setters in the java-like way where you write GetXXX or SetXXX in every sentence of your program.

For me, and I assume for the majority of pascal programmers, the code is more readable if you just put the name of the property you're reading/writing, and we all know a Getter or Setter method will be called (if necessary).

Also, I think it is a huge benefit (and elegance) from the delphi property model that you can get/set the property value directly from a field To have a lot of Get/Set methods with just a line of code where the value is assigned or read from a field is a total waste of effort/time.

jachguate
+7  A: 

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.

Accessing 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;

Controlling access

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; 

Polymorphism

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;
{----- ----- ----- ----- -----}

Default properties

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);

Index

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 GetTop(Index: Integer): Integer;
  function GetLeft(Index: Integer): Integer
  function GetWidth(Index: Integer): Integer
  function GetHeight(Index: Integer): Integer
public
  property Top    Index 0 read GetTop;
  property Left   Index 1 read GetLeft;
  property Width  Index 2 read GetWidth;
  property Height Index 3 read GetHeight;
end;


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

Some resources

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:

Jørn E. Angeltveit