Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Delphi Classes: Property vs Get/Set methods

So I'm kinda new to OO programming. Delphi has properties which are intended to be a "more elegant" way to acess class data than getters/setters (read it here usage of property vs getters/setters in business classes).

When should I use the fields directly and when should I use getters/setters inside the property? I'm gessing only when the data needs to be manipulated, but I'm not sure.

Edit:

Is it wrong to omit a setter that does nothing but return the value of the field itself?

  property Field :integer read FField write FField;
like image 801
rodolfoThePig Avatar asked Mar 05 '15 17:03

rodolfoThePig


2 Answers

Why properties?

For starters, a quick summary from the documentation on properties:

A property, like a field, defines an attribute of an object. But while a field is merely a storage location whose contents can be examined and changed, a property associates specific actions with reading or modifying its data. Properties provide control over access to an object's attributes, and they allow attributes to be computed.

Why not only setter and getter?

Separation of storage and access can indeed be achieved by the use of just getters and setters, and leave the property be. That is true, but the question you link to originates from a language difference: Delphi does have properties, and the answers there already explain why to use them. The two most obvious reasons are (1) cleaner code and (2) assignment capability. I think this answer deals with it quite extensive already.

Furthermore, without the use of properties, getters and setters are always needed, where with properties they are not. Assume a setter implementation, but no getter: a property can directly read the field.

Class completion

When you just declare a property's name and its type, Delphi's class completion defaults to reading a private field and a private setter which sets the private field. Mind that this is just the default configuration, which you again can modify to your needs. When you fully specify the property declaration, class completion will comply and add a private field, a getter and/or setter as required for your declaration.

Properties without getter and setter

Is it wrong to omit a setter that does nothing but return the value of the field itself?

When a property has no getter nor setter and it just reads and writes the field, then you could conclude that there is no difference beside being consistent. But that is not the case. The field and the property have distinct names, and therefore possibly distinct meaning. Meaning that you can give. See Using properties instead of fields in class methods of the same unit is a bad practice?.

When to use a getter or setter?

... I'm gessing only when the data needs to be manipulated ...

Well, that is partly true. Manipulation is one of the many reasons. Consider a Price property of type String, and its private field FPrice:

  • Limitation: When the price needs to be equal or higher than zero,
  • Delegation: When FPrice is part of another field, or when it otherwise is beyond the responsibility of this class,
  • Verification: When the price may only have two decimals behind the comma,
  • Interpretation: When the price is entered in thousands, but should be stored in cents,
  • Effect: When the price has consequences for another field, for example rate or margin,
  • Activation: When an edit to the price requires immediate action, for example updating the GUI,
  • Conversion: When the price is entered in dollars but should be stored in yen,
  • Cancelation: When the price does not make sense, for example when it is entered in scientific notation.

Note that a Price property is quite rudimentary. Leaving its setter or getter for future implementation is very well possible. But imagine more advanced properties which cannot do without setter or getter:

  • A field that needs to be created before consulting:

    function TMyObject.GetBarelyUsed: TRare;
    begin
      if FBarelyUsed = nil then
        FBarelyUsed := TRare.Create(Self);
      Result := FBarelyUsed;
    end;
    
  • An item can be selected, but the item itself does not know what to do. Instead the owner does. Notice the complete absence of the private field in this case:

    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;
    
  • An image control, specialized in viewing your own image format. Assignment of the FileName property involves: checking the correct file extension, checking file existance, storing the file name in the private field, loading the file, adjusting the pictures' dimensions, or else undoing the previous assignment:

    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

like image 119
NGLN Avatar answered Sep 28 '22 01:09

NGLN


In addition to @NGLN answer there is another use case for property getter/setter.

Accessing class instances through interface is only possible via instance methods. If you have to access property in such case you have to implement getter/setter methods.

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;

Of course, depending whether you need only read or write access to that property you can omit setter or getter in your interface declaration.

Keep in mind that accessing instance through interface gives all interface implemented methods public visibility. That is why in above example you can call f.GetField despite it being declared protected (or even private).

like image 34
Dalija Prasnikar Avatar answered Sep 27 '22 23:09

Dalija Prasnikar