Header javaperspective.com
JavaPerspective.com  >   Advanced Tutorials  >   5. Best practice tips  >   5.1. Implementation hiding

5.1. Implementation hiding
Last updated: 1 February 2013.

Implementation hiding is a key concept in object-oriented programming. The idea is to hide the implementation of a class so that changes in the implementation do not affect the public interface of the class. As its name implies, the public interface of a class refers to all the visible elements of the class (typically, the public methods). Hence, if you hide the implementation of a class, the signatures of its public methods must not change even when the implementation of those methods change.

Let's take a basic example to illustrate implementation hiding: Suppose that your application deals with the products of a store. A product is an instance of the class Product shown below:

public final class Product {

   
private int id;
   
private String name;
   
private String reference;
   
private float price;


   
public Product(int id, String name, String reference, float price) {
         
this.id = id;
         
this.name = name;
         
this.reference = reference;
         
this.price = price;
   
}


   
public int getId() {
         
return id;
   
}

   
public String getName() {
         
return name;
   
}

   
public String getReference() {
         
return reference;
   
}

   
public float getPrice() {
         
return price;
   
}

}

A product is uniquely identified by the value of the field id. It also has a name, reference and price. Instances of the class Product are used by the class ProductManager which contains the list of products available within the store. The class ProductManager provides methods to add a new product, get a product and remove a product from the list. Here is the code:

import java.util.ArrayList;
import java.util.List;

public final class ProductManager {

   
private List<Product> listOfProducts = new ArrayList<Product>();


   
public void addProduct(Product product){
         
listOfProducts.add(product);
   
}


   
public Product getProduct(int id){
         
for(Product product : listOfProducts){
               
if(product.getId() == id)
                     
return product;
         
}

         
return null;
   
}


   
public boolean removeProduct(int id){
         
Product productToBeRemoved = null;

         
for(Product product : listOfProducts){
               
if(product.getId() == id)
                     
productToBeRemoved = product;
         
}

         
if(productToBeRemoved != null){
               
listOfProducts.remove(productToBeRemoved);
               
return true;
         
}

         
return false;
   
}

}

The implementation of the class ProductManager is hidden to the other classes. They know what the methods addProduct, getProduct and removeProduct are supposed to do but they do not know how it's done. In particular, the other classes are not aware that the class ProductManager uses an ArrayList to store the products. Thus, if the implementation of the class ProductManager changes, the signatures of the methods addProduct, getProduct and removeProduct will not change.

In this example, you are likely to change the implementation of the class ProductManager in order to improve the overall performance of the application for the following reason: the methods getProduct and removeProduct walk through the list to find the right product every time they are called. Therefore, they will take longer and longer to return as the list grows up. For better performance, if you decide to use a HashMap instead of an ArrayList to store the products, the signatures of the public methods do not need to change. See the code below:

import java.util.HashMap;
import java.util.Map;

public final class ProductManager {

   
private Map<Integer, Product> mapOfProducts = new HashMap<Integer, Product>();


   
public void addProduct(Product product){
         
mapOfProducts.put(product.getId(), product);
   
}


   
public Product getProduct(int id){
         
return mapOfProducts.get(id);
   
}


   
public boolean removeProduct(int id){
         
if(mapOfProducts.containsKey(id)){
               
mapOfProducts.remove(id);
               
return true;
         
}

         
return false;
   
}

}

As you can see, the implementation of the class ProductManager has changed but the signatures of the public methods remain the same. Consequently, the calls to those methods within the application also remain unchanged. Especially, if those methods are called from numerous locations within the application, you can avoid the hassle of changing each and every call. For this reason, implementation hiding is highly recommended in object-oriented programming.

In fact, if we get back to the first version of the class ProductManager, you might have been tempted to remove the method addProduct since it only contains a single statement and expose the list of products to the other classes by providing a getter which returns the list as follows:

import java.util.ArrayList;
import java.util.List;

public final class ProductManager {

   
private List<Product> listOfProducts = new ArrayList<Product>();


   
public Product getProduct(int id){
         
for(Product product : listOfProducts){
               
if(product.getId() == id)
                     
return product;
         
}

         
return null;
   
}


   
public boolean removeProduct(int id){
         
Product productToBeRemoved = null;

         
for(Product product : listOfProducts){
               
if(product.getId() == id)
                     
productToBeRemoved = product;
         
}

         
if(productToBeRemoved != null){
               
listOfProducts.remove(productToBeRemoved);
               
return true;
         
}

         
return false;
   
}


   
public List<Product> getListOfProducts() {
         
return listOfProducts;
   
}

}

With the version of the class ProductManager shown above, the code to add a new product from another class would look something like this:

Product product = new Product(33, "Microwave oven", "AKR-342-G", 90.5F);
productManager.getListOfProducts
().add(product);

The implementation of the class ProductManager is not hidden anymore because ProductManager now reveals to the other classes that it uses an ArrayList to store the products. If that ArrayList is replaced by a HashMap, all the statements throughout the application that add a product to the ArrayList would have to be modified.


You are here :  JavaPerspective.com  >   Advanced Tutorials  >   5. Best practice tips  >   5.1. Implementation hiding
Next tutorial :  JavaPerspective.com  >   Advanced Tutorials  >   5. Best practice tips  >   5.2. Interface type variables

Copyright © 2013. JavaPerspective.com. All rights reserved.  ( Terms | Contact | About ) 
Java is a trademark of Oracle Corporation
Image 1 Image 2 Image 3 Image 4 Image 5 Image 6 Image 7