Accessing Object Properties While Respecting Encapsulation

Despite object oriented programming having been mainstream for well over a decade now, there are still concepts associated with it that are sources of confusion for its practitioners. It seems to me that, unfortunately, easily available guidance is still in short supply. One source of problems is this: how should an object should make information about itself available to its client code while respecting the principle of encapsulation? Sadly, all too frequently, encapsulation is abandoned in favour of “get/set” methods that are effectively just public data members in disguise.

It is quite possible for objects, in their public interfaces, to share information about themselves with their client code while respecting encapsulation. It is my goal in this article to show how this can be done, and in doing so, to clear up some of the misunderstandings surrounding encapsulation in this respect.

Let’s start with an example, let’s design a Circle class. Normally, when designing a class, the first thing I would think about is its public interface methods, and for illustration purposes I’m just going to pick on one method: one to return the circle’s radius. Here is a C# code fragment showing this:

    class Circle
    {
        public uint Radius
        { 

            ...
        } 

        ...
    }

This is saying that, as a design matter, circle has a property called Radius. Here property is a critical word. In their public interfaces, objects expose properties – that is, pieces of information about themselves which client code can read. Client code can now read a circle’s radius as follows:

    class UsesCircle
    {
        static void Example(Circle the_circle)
        {
            uint radius = the_circle.Radius;
        }
        ...
    }

Now before we move on, there are a couple of things I would like to draw attention to:

  • My examples in this article are in C#, and C# supports properties as a language feature. In languages that don’t directly support properties – C++ for example – then simple value returning methods are typically used instead
  • I have deliberately avoided using the name GetRadius in favour of Radius – I believe this is closer to how it would be expressed in English, and is therefore a more natural naming
  • You may be wondering: what about updating Radius? Well, you can’t directly update it, and sorry, but (in the interests of keeping this article down to a reasonable length) I’m deferring the explanation of that until part 2

Time now to think about how to implement the Circle class. The obvious way is to store both the centre point and the radius as data members: that would mean the Radius property would just return the radius data member, as you might expect. However, just to make a point I’m going to do things a little differently: I’m store the centre point, nothing different there, but rather than store the radius I’m going to store the diameter of the circle. Here’s a fragment of the implementation:

    class Circle
    {
        public uint Radius
        {
            get { return diameter_ / 2; }
        }

        ...

        private int x_centre, y_centre;
        private uint diameter_;

        ...
    }

Obviously the Radius property must now do a simple division, and return half the radius. As I said above, I’ve done it this way to make a point: this is possible because the Radius property encapsulates its implementation!

Now let’s re-implement the class using a more obvious approach: storing the radius as a data member:

    class Circle
    {
        public uint Radius
        {
            get { return radius_ ; }
        }

        // ...

        private int x_centre, y_centre;
        private uint radius_;

        // ...
    }

Now we’re back to having the Radius property just returning the value of a data member. However the point is this: the interface was designed to make the radius property readable, and it just so happens that the chosen implementation is one that returns the value of a data member! The idea is supported by the simple fact that – as illustrated above – alternative implementations are possible. As a further example, the circle could store its centre and two circumference points, although the calculation needed in Radius‘s implementation would be slightly more complicated. Note in passing that this encapsulation is underpinned by keeping member data private.

When designing a class, programmers need to effectively put themselves on the outside and look inwards. That is, consider what interface is required – including readable properties – and then move inside the class and consider how to implement them. This is the way of encapsulation. This is a very different thing to the all too common approach of simply exposing a data member through a public property!

I hope this article has helped to clear up some misconceptions and misunderstandings. It is far from the end of the story. I still have to deal with how to design in cases where properties can be updated, and no doubt this is not the only unanswered question. I hope to write up part 2 soon.

Leave a Comment

Your email address will not be published. Required fields are marked *