August 27, 2014
Hot Topics:
RSS RSS feed Download our iPhone app

Packaging Objects to Preserve Encapsulation

  • September 7, 2005
  • By Matt Weisfeld
  • Send Email »
  • More Articles »

This series, The Object-Oriented Thought Process, is intended for someone just learning an object-oriented language and wants to understand the basic concepts before jumping into the code or someone who wants to understand the infrastructure behind an OOP language they are already using. Click here to start at the beginning of the series.

In keeping with the code examples used in the previous articles, Java will be the language used to implement the concepts in code. One of the reasons that I like to use Java is because you can download the Java compiler for personal use at the Sun Microsystems Web site http://java.sun.com/. You can download the J2SE 1.4.2 SDK (software development kit) to compile and execute these applications and I will provide the code listings for all examples in this article. I have the SDK 1.4.0 loaded on my machine. I will also provide figures and the output (when appropriate) for these examples. See the previous articles in this series for detailed descriptions for compiling and running all the code examples in this series.

In the previous column we asked the question: does inheritance weaken encapsulation? We were able to prove with a code example that we are indeed able to do some things with inheritance that is questionable with regards to the encapsulation rule. Let's do a quick review of the problem and the 2 important rules that appear to conflict with each other.

The Potential Problem Revisited

Whenever the interface/implementation paradigm is covered, we are really talking about encapsulation. The basic question is what in a class should be exposed and what should not be exposed. This encapsulation pertains equally to data and behavior. When talking about a class, the primary design decision revolves around encapsulating both the data and the behavior into a well-written class.

Inheritance is a mechanism by which a developer can design one class by inheriting the data and behavior of another class. For example, a Dog class can inherit data and behavior from a Mammal class. Thus, the designer can create data and behavior for all mammals and not have to duplicate this functionality for various mammals like dogs, cats, bears, etc.

Encapsulation is so fundamental to OO that enforcement of encapsulation is one of OO design's cardinal rules. Inheritance is also considered one of the three primary OO concepts. However, in the previous column we found that, at least, in one way, inheritance actually breaks encapsulation!

Let's deal with this problem by modifying the code that we were working on in the last article (we will start with a bit of a review).

A Code Example

In this example we created 3 classes, Mammal, Dog, and an application class called Packaging. The reason that we named the application Packaging was due to the fact that we are going to address our encapsulation/inheritance dilemma by using Java packaging. The Mammal class is shown in listing 1.

// Class Mammal
public class Mammal {
 private String color;
 public void growHair(){
  System.out.println("Hair Growing");
 }
}

Listing 1

In this class we have a private attribute called color and a public method called growHair(). To use the Mammal class we create an application called Packaging. This class is presented in listing 2.

//Class Packaging
public class Packaging {
 public static void main (String args[]){
     
  Mammal mammal = new Mammal();
    
  mammal.growHair();
  mammal.color = "blue";
          
    }
 
}

Listing 2

When we run this application we get the output in figure 1.

Figure 1

We can now test our encapsulation principle by attempting to have the application access the private attribute color as seen in listing 3.

//Class Packaging
public class Packaging {
 public static void main (String args[]){
     
  Mammal mammal = new Mammal();
    
  mammal.growHair();
  mammal.color = "blue"; // try to access private attribute
          
    }
 
}

Listing 3

As we can see in figure 2, the compiler just won't accept this.

Figure 2

This was all expected; however, let's add inheritance to the mix by adding a class called Dog as seen in listing 4.

//Class Dog
public class Dog extends Mammal{
 private int barkFrequency;
 public void bark(){
  System.out.println("Dog Barking"); 
 }
    
}

Listing 4

Now we can start doing some interesting things. First, we can try to access Mammal's attribute color from the Dog class - see listing 5.

//Class Dog
public class Dog extends Mammal{
 private int barkFrequency;
 public void bark(){
  System.out.println("Dog Barking"); 
  color = "blue"; 
 }
    
}

Listing 5

When we run this the compiler complains again as is seen in figure 3. Yet, at one level this appears incorrect. Since Dog Is-A Mammal, doesn't the Dog contain all the attributes of Mammal? In short, is in not true that Dog inherits all the attributes and methods of Mammal?

Figure 3

This is an interesting design dilemma for object-oriented compiler builders. Here is the problem.

  • Inheritance dictates that a child class (subclass) inherits all the attributes and methods from a parent class (superclass).
  • Encapsulation dictates that one class must not have access to the (private) data of another class.

The way these rules are written it seems that, at least in one point, they may be mutually exclusive. How can this conundrum be addressed?

Since encapsulation is the primary object-oriented mandate we have no choice, we must make all attributes private. Making the attributes public is not an option. Thus, it appears that the use of inheritance may be severely limited. The important question is this: if a subclass does not have access to the attributes of its parent then we have a real design problem.

To allow subclasses to access the attributes of the parent, language designers have included the access modifier protected. There are actually 2 types of protected access, which we will explain in detail later in this column. Right now, let's change the color access modifier to protected as seen in listing 6.

// Class Mammal
public class Mammal {
 protected String color;
 public void growHair(){
  System.out.println("Hair Growing");
 }
}

Listing 6

This change allows the code to compile and execute. By making color protected, Dog now has access to the attributes in Mammal - as we would expect. However, we now have another problem.

In listing 9 we put back the line to access Dog's color attribute from the Packaging application.

//Class Packaging
public class Packaging {
 public static void main (String args[]){
  Mammal mammal = new Mammal();
  mammal.growHair();
  mammal.color = "blue";
    }
}

Listing 7

The problem is that this compilation process now works (see figure 4). In short, the application (class Packaging) can directly access Dog's color attribute (via its parent Mammal). This is due to the fact that the protected modifier allows classes in the same package to access each others protected attributes. In this case we have created no packages so the Java compiler puts everything in a default package.

Note: if you create a Java file without defining a package at the top of the file, then the class is placed in the default package. The Sun online documentation suggests the following: "Generally speaking, the default package is only for small or temporary applications or when you are just beginning development. Otherwise, classes, enums and annotations belong in named packages."

Regardless of what is going on, the application has direct access to an attribute in another class. Based on the rule of encapsulation, this is unacceptable. It appears that we have fixed the inheritance issue, but now we have broken encapsulation. What can we do?

Figure 4

We clearly have a dilemma. It appears that we have to make a decision as to whether to enforce inheritance or encapsulation. This example clearly shows the problem that inheritance poses to encapsulation. It is very helpful for a developer to fully understand the subtleties involved with the inner workings of various object-oriented constructs. By realizing what the issues are in this example, you can more fully grasp what inheritance and encapsulation are and how to make your designs more robust.





Page 1 of 2



Comment and Contribute

 


(Maximum characters: 1200). You have characters left.

 

 


Sitemap | Contact Us

Rocket Fuel