Data Hiding & Encapsulation
Home ] Up ] What is Inheritance? ] Inheritance versus Containment ] Superclasses & Subclasses ] Visibility Modifiers & Inheritance ] Final Classes & Methods ] Polymorphism ] [ Data Hiding & Encapsulation ] Abstract Classes ] Interfaces ] Cloning Objects ] The Collections Framework ] Interfaces & Callbacks ]

 

 

Hide Your Class Implementation!

One of the most powerful and important features of languages like Java is that it allows you to hide the implementation of your class. This is called data hiding, or encapsulation.

Why would you want to do this?

Because, by allowing the clients of your class:

  • knowledge of the class interface
  • and no knowledge of the class implementation

you can insulate those clients from any changes you make in the class implementation. And, in any non-trivial class, you will make changes!

Another reason is to protect you and your clients from accidental or willful misuse. Typically, the implementation relies on complex interrelationships among data and methods. It is not reasonable to expect that all clients, given some knowledge of the implementation, will use that knowledge wisely.

The Levels of Interface for a Class

Every class can be viewed from a number of perspectives (interfaces):

  • From inside the class itself (implementation)
  • From classes within the class's package (mostly implementation)
  • From the outside world (public interface)
  • From subclasses of that class (inheritance interface)

Note: even if there are no subclasses today, there may well be in the future!

Note: When you design a class, you should think about which parts of that class should be part of each of these interfaces.

How to Hide Your Class Implementation

You should make a habit of designing your classes using a very conservative model:

  • Make all of your class attributes (data) private
class MyClass
{
    /* ... */
    private String m_name;
};
  • For each class attribute that your clients need to access:
    • For each attribute that needs read access, provide a public accessor method:
      class MyClass
      {
          /* ... */
          public String name()	{ return m_name; }
          private String m_name;
      };
    • For each attribute that needs write access, provide a public mutator method:
      class MyClass
      {
          /* ... */
          public void name(String name){ m_name = name; }
          private String m_name;
      };
    • Choose the naming convention:
      • Type getFoo()
      • void setFoo(Type value)

      where:

      • foo is the name of the attribute
      • Type is the datatype of that attribute
  • For each class method:
    • If the method is part of the public interface
      • Make sure it really is part of the public interface!
      • If it is, make it public
      • If it's not, do not make it public!
    • A method that is part of the class's implementation
      • If the method is used by other classes in the same package
        • Give it package visibility (no visibility modifiers)
        • Note that this amounts to it being part of the package interface
      • If the method is used only by this class
        • Make it private
    • A method that is part of the class's inheritance interface
      • Make it protected
      • Make sure that you provide the necessary attribute accessor/mutator methods with the protected attribute (don't make an attribute itself protected!)

Common mistakes

  • Not making all class attributes (data) private
  • Making too many methods public
  • Making a class attribute (data) protected instead of creating protected accessor/mutator methods
  • Making a method public, when it should be made protected
 

This page was last modified on 02 October, 2007