Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does it violate encapsulation for interface property accessors to be public?

When we design a class in Delphi, typically we have private fields (members), private setter and getter methods and a public property. From outside the class, the access of that data is made only by the public property; the users of the class don't even know that a getter method exists.

So the getter and setter methods encapsulate the instance member and the property encapsulates the getter and setter methods.

However, when defining an interface we are exposing those methods:

ICounter = interface
  // I wouldn't want to specify these 2 methods in the interface, but I'm forced to
  function GetCount: Integer;
  procedure SetCount(Value: Integer);

  property Count: Integer read GetCount write SetCount;
end;

Implementing the concrete class:

TCounter = class(TInterfacedObject, ICounter)
private
  function GetCount: Integer;
  procedure SetCount(Value: Integer);
public
  property Count: Integer read GetCount write SetCount;
end

Using it:

var
  Counter: ICounter;
begin
  Counter := TCounter.Create;
  Counter.Count := 0; // Ok, that's my public property

  // The access should me made by the property, not by these methods
  Counter.SetCount(Counter.GetCount + 1);
end;

If the properties encapsulate the getter/setter private methods, isn't this a violation? The getter and setter are the internals of the concrete class and shoudn't be exposed.

like image 337
Rafael Piccolo Avatar asked Dec 20 '22 21:12

Rafael Piccolo


1 Answers

Methods are the primary way of interacting with an interface. Properties on interfaces are a Delphi-specific extension; they just provide syntactic sugar for the underlying methods. No other language Since methods in interfaces are by definition public, they are not encapsulated by properties. You're not revealing any implementation details by showing that a property is backed by methods because in interfaces, properties are always backed by methods, and methods are always public. Encapsulation cannot be violated if it was never present in the first place.

Your example concrete class is misleading. First, the property defined there has absolutely no connection to the property defined in the interface. You could define it as read-only, make it directly access data members, make it private, or differ from the interface version in any other way, including remove it entirely, and it would have no effect on users of the interface, lending further credence to the notion that it's the methods that matter in an interface, not the properties. The compiler translates any use of the interface property directly into use of one of the corresponding interface methods, which are already public. The implementing object is never consulted on the matter.

Second, the visibility specifiers on the class are irrelevant. There's no need to make the methods private since they're public on the interface already. However, making them private isn't a bad idea since it encourages proper use of the class via the interface.

You could complain that the accessor methods of an interface should be able to be private, but that's the same as asking for interface methods in general to be able to be private, and that makes no sense. A method that can't be called obviously isn't part of the interface. Recall that interfaces can be consumed by any COM-supporting language, even ones that have no notion of properties, like C and C++. Those languages need to be able to call the accessor methods, too. If the methods were somehow private, the interface wouldn't work in those languages.


When a property of a Delphi class refers to a field, that detail is actually part of the class's public-facing interface. Any code that uses that property knows that the property is just an alias for the field (even if the author of the code didn't know that). If you change the property definition, any code using that class needs to be recompiled so the compiler can generate new code for accessing the property.

When properties are required to be backed by methods, you can't really change the property definition anymore. Only the implementation can change, and so no consumers of the interface need recompiling just because you choose to make a property be calculated on demand instead of read from a stored field.

like image 105
Rob Kennedy Avatar answered Dec 24 '22 01:12

Rob Kennedy