You are here

Information Hiding

6 June, 2016 - 14:19
Available under Creative Commons-ShareAlike 4.0 International License. Download for free at http://cnx.org/contents/402b20ad-c01f-45f1-9743-05eadb1f710e@37.6

Information hiding is a tried-and-true design principle that advocates hiding all implementation details of software components from the user in order to facilitate code maintenance. It was first formulated by David L. Parnas (in 1971-1972) as follows.

  • One must provide the intended user with all the information needed to use the module correctly and nothing more.
    • translation to OOP: the user should not know anything about how an interface or abstract class is implemented. For example, the user need not and should not know how IList is implemented in order to use it. The user should only program to the abstract specification.
  • One must provide the implementor with all the information needed to complete the module and nothing more.
    • translation to OOP: the implementor of a class or an interface should not know anything about how it will be used. For example, the implementor need not and should not know how, when, or where IList will be used. The implementor should write the implementation code based solely on the abstract specification.

By adhering to the above, code written by both users and implementors will have a high degree of flexibility, extensibility, interoperability and interchangeability.

The list framework that we have developed so far has failed to hide MTList and NEList, which are concrete implementations of IList, the abstract specifcation of the list structure. In many of the list algorithms that we have developed so far, we need to call on MTList.Singleton or the constructor of NEList to instantiate concrete IList objects. The following is another such examples.

InsertInOrder.java
import listFW.*;
/**
 * Inserts an Integer into an ordered host list, assuming the host list contains
 * only Integer objects.
 */
public class InsertInOrder implements IListAlgo {
    public static final InsertInOrder Singleton = new InsertInOrder();
    private InsertInOrder() {
    }
    /**
     * This is easy, don't you think?
     * @param inp inp[0] is an Integer to be inserted in order into host.
     */
    public Object emptyCase(MTList host, Object... inp) {
        return new NEList(inp[0], host);
    }
    /**
     * Delegate (to recur)!
     * @param inp inp[0] is an Integer to be inserted in order into host.
     */
    public Object nonEmptyCase(NEList host, Object... inp) {
        int n = (Integer)inp[0];
        int f = (Integer)host.getFirst();
        return n < f ?
                new NEList(inp[0], host):
                new NEList(host.getFirst(), (IList)host.getRest().execute(this, inp[0]));
    }
}
 
 

The above algorithm to insert in order an integer into an ordered list of integers can only be used for a very specific implementation of IList, namely the one that has MTList and NEList as concrete subclasses. How can we write list algorithms that can be used for ANY implementation of the abstract specification of the list structure represented by the abstract class IList?

We can achieve our goal by

  1. abstracting the behavior of MTList and NEList into interfaces with pure abstract structural behaviors.
  2. applying the Abstract Factory Design Pattern to hide the concrete implementation from the user.