5

According to the essay "The Object Calisthenics" by Jeff Bay in the book ThoughtWorks Anthology, Use of Getters and Setters should be avoided as they break encapsulation and we should instead ask the object to do something for us instead of digging in to the object and getting its fields.

how about comparison of objects ?

I have to find best object say a Resort for the customer on the basis of a rule that uses few properties of the Resort object.

This rule can change in future. So I find use of comparator interface better as compared to comparable interface. But then I will have to use getters and setters for to access individual properties to compare to objects in a different class.

Amogh Talpallikar
  • 1,997
  • 2
  • 26
  • 39

3 Answers3

13

Books can be wrong or misleading. It is certainly true that having getters and setters for every field provides little more encapsulation than having those fields be public, and it's unfortunate that this kind of design is very widespread.

But it's nonsense to conclude that getters and setters should be avoided altogether. Instead, they should be added deliberately where appropriate, as part of the API design of the class:

  1. If everything a field does can be handled by domain-specific methods, don't have a getter or setter - this is the best case.
  2. If the value of a field is by itself useful and necessary for other classes, add a getter (not a setter)
  3. If the fields represents something like a configuration value, a way for the behaviour of the object to be influenced from outside, add a setter (and a getter iff knowing this configuration could also be useful to other classes).

A Comparator could be seen as an example for case 2, especially if the Comparator is deliberately used instead of having the class implement Comparable. This indicates that the comparison logic is external to the class, and it depends on the field, so the field is useful outside the class.

A compromise might be to have a package private (default visibility) getter and keep the comparator in the same package - or even have it as an inner class that accesses the private field. That would be appropriate if you want the class itself to offer a choice of different sort orders.

If your only concern is that the sort order may change globally in the future, I'd actually stay with Comparable - it's still a change in once place, no need to separate it artificially.

Michael Borgwardt
  • 51,037
  • 13
  • 124
  • 176
  • 1
    +1 the points presented in Object Calisthenics are just thought-provoking guidelines, in fact the author explicitly states that you shouldn't treat them as "rules" in normal practice. – MattDavey May 02 '12 at 10:07
  • @MattDavey: Actually he emphasized on trying them on a small project and they themselves have strictly followed these rules on big serious projects. So I was using it on a problem I faced in their selection process few months ago. So when I just saw this exercise and then I thought let me solve the problem under these guidelines and see what all I wrote in my code which made it less object-oriented. and now I have realized a lot of it was nowhere near their standards. But in general I want to improve upon my skills and design habits. Thx to this trial I have started thinking differently. – Amogh Talpallikar May 02 '12 at 10:19
  • I would agree that the best implementation of Comparator is as an inner class (maybe even anonymous). Gets rid of the whole breaking encapsulation thing ;) – Michael Brown May 02 '12 at 12:31
7

Encapsulation is hiding implementation details from outer world, in order to make implementation changes transparent. The very notion of "outer world" assumes existence of some "inner world". But where are the boundaries? They do not always have to be identical to the class boundaries. Often several classes are tightly dependant and can be seen as monolithic programming entity, for example, arcs and nodes in a graph implementation. In such a case, it's ok to use not only getters and setters, but even direct access to fields of siblings classes.

In your case, use Comparator if you like it. To underscore the fact that it belongs to the same programming entity as the class being compared (Resort), you can make it a static class inside the Resort class. Then you'll be able to access private fields of Resort from the comparator.

1

Object calisthenics is not meant to be taken as a series of rules on OO design, rather they are designed to provoke a new thought process. Taking your scenario for example, and working within the boundaries of Object Calisthenics, I might take an approach wildly different to what I normally would have taken..

enum ResortFacility
{
    Pool,
    Sauna,
    Gym,
    Daycare
}

class Resort
{
    private ResortFacility[] facilities;

    boolean HasFacility(ResortFacility facility)
    {
        return facilities.Contains(facility);
    }
}

class CustomerRequirements
{
    private ResortFacility[] requiredFacilities;

    public boolean AreMetBy(Resort resort)
    {
        return requiredFacilities.All(required => resort.HasFacility(required));
    }
}


// possible usage:
var customerRequirements = new CustomerRequirements(ResortFacility.Pool, ResortFacility.Gym);

var resortA = new Resort(ResortFacility.Daycare);
var resortB = new Resort(ResortFacility.Pool, ResortFacility.Sauna);
var resortC = new Resort(ResortFacility.Pool, ResortFacility.Gym);

customerRequirements.AreMetBy(resortA) == false;
customerRequirements.AreMetBy(resortB) == false;
customerRequirements.AreMetBy(resortC) == true;

Again, whether this approach has sufficient value over a much simpler public property comparison is something to consider.

MattDavey
  • 7,096
  • 3
  • 31
  • 32
  • Although my problem was about Resorts having differen rates on weekdays and weekends that too for different type of customer: reward and regular. and I needed to find cheapest hotel out of 4-5 depending on series of dates as input. Just in case the prices tie, i would consider one with higher rating (out of 5). But still thanks for the code and use of lambda expressions. they just blow the minds of a java dev writing objects implementing interfaces with single methods. But I got your point of times when we cant avoid getters or setters. – Amogh Talpallikar May 02 '12 at 10:45