You are here

Abstract List Factory

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

Before we describe in general what the Abstract Factory Pattern is, let's examine what we have to do in the case of IList.

  • Define an abstract factory interface, IListFactory, to manufacture empty and non-empty IList objects. Put IList, IMTList, INEList, IListVistor, and IListFactory in the same pack age. IListFactory is specified as followed.
IListFactory.java
package listFW;
/**
 * Abstract factory to manufacture IMTList and INEList.
 */
interface IListFactory {
    /**
     * Creates an empty list.
     * @return an IMTList object.
     */
    IMTList makeEmptyList();
    /**
     * Creates a non-empty list containing a given first and a given rest.
     * @param first a data object.
     * @param rest != null, the rest of the non-empty list to be manufactured.
     * @return an INEList object containing first and rest
     * @exception IllegalArgumentException if rest is null.
     */
    INEList makeNEList(Object first, IList rest);
}
 
 

IList, IListAlgo, and IListFactory prescribe a minimal and complete abstract specification of what we call a list software component. We claim without proof that we can do everything we ever want to do with the list structure using this specification.

  • All algorithms (i.e. visitors) that call for the creation of concrete IList objects will need to have an abstract factory as a parameter and use it to manufacture IList objects. We usually pass the factory as an argument to the constructor of the visitor. The visitor is thus not a singleton.
InsertInOrderWithFactory.java
import listFW.*;
/**
 * Inserts an Integer into an ordered host list, assuming the host list contains
 * only Integer objects.  Has no knowledge of how IList is implemented.  Must
 * make use of a list factory (IListFactory) to create IList objects instead of
 * calling the constructors of concrete subclasses directly.
 */
public class InsertInOrderWithFactory implements IListAlgo {
    private IListFactory _listFact;
    public InsertInOrderWithFactory(IListFactory lf) {
        _listFact = lf;
    }
    /**
     * Simply makes a new non-empty list with the given inp parameter as first.
     * @param host an empty IList.
     * @param inp inp[0] is an Integer to be inserted in order into host.
     */
    public Object emptyCase(IMTList host, Object... inp) {
        return _listFact.makeNEList(inp[0], host);
    }
    /**
     * Recur!
     * @param host a non-empty IList.
     * @param inp inp[0] is an Integer to be inserted in order into host.
     */
    public Object nonEmptyCase(INEList host, Object... inp) {
        int n = (Integer)inp[0];
        int f = (Integer)host.getFirst();
        return n < f ?
                _listFact.makeNEList(inp[0], host):
                _listFact.makeNEList(host.getFirst(),
                                    (IList)host.getRest().execute(this, inp[0]));
    }
}
 
 

The above algorithm only "talks" to the list structure it operates on at the highest level of abstraction specified by IList and IListFactory. It does know and does not care how IList and IListFactory are implemented. Yet it can be proved to be correct. This algorithm can be plugged into any system that subscribes to the abstract specification prescribed by IList, IListAlgo, and IListFactory.

  • Provide a concrete implementation of the abstract factory that contains all concrete subclasses of IList as private static classes and thus hide them from all external code.
CompositeListFactory.java
package listFW.factory;
import listFW.*;
/**
 * Manufactures concrete IMTList and INEList objects.  Has only one
 * instance referenced by CompositeListFactory.Singleton.
 * MTList and NEList are static nested classes and hidden from all external
 * client code.  The implementations for MTList and NEList are the same as
 * before but completely invisible to the outside of this factory.
 */
public class CompositeListFactory implements IListFactory {
    /**
     * Note the use of private static.
     */
    private static class MTList implements IMTList {
        public final static MTList Singleton = new MTList ();
        private MTList() {
        }
        final public Object execute(IListAlgo algo, Object... inp) {
            return algo.emptyCase(this, inp);
        }
        public String toString() {
            return "()";
        }
    }
    /**
     * Note the use of private static.
     */
    private static class NEList implements INEList {
        private Object _first;
        private IList _rest;
        public NEList(Object dat, IList rest) {
            _first = dat;
            _rest = rest;
        }
        final public Object getFirst() {
            return _first;
        }
        final public IList getRest() {
            return _rest;
        }
        final public Object execute(IListAlgo algo, Object... inp) {
            return algo.nonEmptyCase(this, inp);
        }
        public String toString() {
            return (String)ToStringAlgo.Singleton.nonEmptyCase(this);
        }
    }
    /**
     * Singleton Pattern
     */
    public static final CompositeListFactory Singleton = new CompositeListFactory();
    private CompositeListFactory() {
    }
    /**
     * Creates an empty list.
     * @return an IMTList object.
     */
    public IMTList makeEmptyList() {
        return MTList.Singleton;
    }
    /**
     * Creates a non-empty list containing a given first and a given rest.
     * @param first a data object.
     * @param rest != null, the rest of the non-empty list to be manufactured.
     * @return an INEList object containing first and rest
     */
    public INEList makeNEList(Object first, IList rest) {
        return new NEList(first, rest);
    }
}
 
 
  • Pass such a concrete factory to all client code that need to make use of the abstract factory to manufacture concrete IList instances.

Below is an example of a unit test for the InsertInOrderWithFactory algorithm.

Test_InsertInOrderWithFactory.java
package listFW.visitor.test;
import listFW.*;
import listFW.factory.*;
import listFW.visitor.*;
import junit.framework.TestCase;
/**
 * A JUnit test case class.
 * Every method starting with the word "test" will be called when running
 * the test with JUnit.
 */
public class Test_InsertInOrderWithFactory extends TestCase {
  public void test_ordered_insert() {
    IListFactory fac = CompositeListFactory.Singleton;
    IListAlgo algo = new InsertInOrderWithFactory(fac);
    IList list0 = fac.makeEmptyList();   
    assertEquals("Empty list", "()", list0.toString());
    IList list1 = (IList) list0.execute(algo, 55);
    assertEquals("55->()", "(55)", list1.toString());
    IList list2 = (IList) list1.execute(algo, 30);
    assertEquals("30->(55)", "(30, 55)", list2.toString());
    IList list3 = (IList) list2.execute(algo, 100);
    assertEquals("100 -> (30, 55)", "(30, 55, 100)", list3.toString());
    IList list4 = (IList) list3.execute(algo, 45);
    assertEquals("45->(30, 55, 100)", "(30, 45, 55, 100)", list4.toString());
    IList list5 = (IList) list4.execute(algo, 60);
    assertEquals("60 -> (30, 45, 55, 100)", "(30, 45, 55, 60, 100)", list5.toString()); 
  }  
}
 
 

The above design process is an example of what is called the Abstract Factory Design Pattern. The intent of this pattern is to provide an abstract specification for manufacturing a family of related objects (for examples, the empty and non-empty IList) without specifying their actual concrete classes thus hiding all details of implementation from the user.

Our example of the list structure framework successfully delineates specification from implementation and faithfully adheres to the principle of information hiding.

  • IList, IMTList, INEList, IListAlgo, and IListFactory provide a minimal and complete abstract specification.
  • InsertInOrderWithFactory is a concrete implementation of IListAlgo that performs a concrete operation on the host list. Yet this algorithm need only communicate with the list structure and the list factory via their public interface. It will work with any implementation of IList and IListFactory.
  • CompositeListFactory is a concrete implementation of IListFactory. It uses the composite pattern and the visitor pattern to implement IList. It only communicates with IListAlgo at and knows nothing about any of its concrete implementation. The private static attributes provide the proper mechanism to hide all implementation details from all code external to the class.

Click here to access the complete javadoc documentation and UML class diagram of the list component10 described in the above.

Click here to download the complete source code and documentation of the list component described in the above.