COMP 310
Spring 2010

Lec06: Abstracted Construction using Factories

Home  Info  Owlspace  Resources

The 4 Pillars of Abstraction:

  1. Abstract Structure
  2. Abstract Behavior
  3. Abstract Construction
  4. Abstract Environment

 

Faking Out the GUI with Factories

If the GUI is decoupled from the actual mechanics of Ballworld, how is it able to manage the arbitrary combining of strategies and the subsequent construction of a ball from an arbitrarily combined strategy?

The problem is that the "Add to lists" button doesn't initiate the construction of an strategy object, it only give the system the ability to use a strategy, either for combining or ball instantiation. 

A common "traditional" solution is to save a string object that is the strategy's name and then parse the string to figure out if it is a compound strategy and if so, what its components are.   The problem here is that the act of clicking the "Add to lists" button clearly defines the need to include that specific strategy in the system and the act of clicking the "Combine!" button clearly defines the creation of a binary pair of strategies, but the knowledge of both of these clear acts is lost when that information is encoded as a string that needs to be subsequently parsed.

In an OO system, you always want to capture all the information when it happens and not have to reconstruct it later because part of the information was subsequently lost.

How do we accomplish the full capture of information in this situation?

The trick is the properly abstract what exactly the buttons are doing.    Note that netiher the Add to lists nor Combine! buttons care about the specifics of what strategy(s) they are adding or combining.   What they are really doing is to specify the desire to construct the strategy at some later time.   That is, what the two buttons are doing is to add the ability to construct the specified strategy or the ability to construct the specified strategy pair.

But yet, the system, and especially the GUI, still does not care about the specifics of that construction.   Hence, factories.

What the Add to lists and Combine! buttons do is to add a factory to the system that can construct the desired strategy or strategy pair:

  /**
   * An interface that defines a factory that instantiates 
   * a specific IUpdateStrategy
   */
  private interface IStrategyFac { 
	/**
	 * Instantiate the specific IUpdateStrategy for which this factory is defined.
	 * @return An IUpdateStrategy instance.
	 */
    public IUpdateStrategy make();
  }
  
  /**
   * Command that is invoked by clicking the "Add to lists" button on the GUI.
   */
  private ILambda _addCmd =  new ILambda(){
    /**
     * Returns an IStrategyFac that can instantiate the strategy specified by classname.
     * Returns null if classname is null.
     * The toString() of the returned factory is the classname.
     */
    public Object apply(final Object classname) {
      if(null==classname) return null;
      return new IStrategyFac() {
        public IUpdateStrategy make() {
          return loadStrategy(fixName(classname));          
        }
        public String toString() {
          return classname.toString();
        }
      };
    }
  }; 
  
  /**
   * Command that is invoked by clicking the "Combine!" button on the GUI.
   */
  private ILambda _combineCmd =  new ILambda(){
	/**
	 * Returns an IStrategyFac that can instantiate a MultiStrategy with the two strategies
	 * made by the two given IStrategyFac objects.
	 * Returns null if either supplied factory is null.
	 * The toString() of the returned factory is the toString()'s of the two given factories, concatenated with "-".
	 * @param o An array of Objects, which has two elements, both of which are IStategyFac objects. 
	 */
    public Object apply(Object o) {
      final Object[] facPair = (Object[]) o; // for convenience
      if(null==facPair[0] || null==facPair[1]) return null;
      return new IStrategyFac() {
        public IUpdateStrategy make() {
          return new MultiStrategy(((IStrategyFac)facPair[0]).make(),
                                   ((IStrategyFac)facPair[1]).make());          
        }
        public String toString() {
          return facPair[0].toString()+"-"+facPair[1].toString();
        }
      };
    }
  }; 
The drop-lists on the GUI are JComboBox's, which most people simply load with strings to display.   However, JComboBox actually takes Objects, not Strings.   The drop-list is created by the displaying the return value of each object's toString() method.    All the Add to lists and Combine! buttons do is run their respective commands and add the returned Object to both drop-lists.   All the Make Selected Ball button does is to run a command that uses the selected factory to instantiate the strategy for a new Ball.

Notice that the GUI only deals with Objects, not IStrategyFac's.  In fact, the GUI never knows about the existence of the factories.   The job of the GUI is to specify that selections for adding and combining have been made, not what those choices actually do or how they do it.   Hence, IStrategyFac is a private interface completely inside of the controller.

The key to proper design here was the recognition that the system could be expressed in terms of an abstract construction process.

 

An interesting viewpoint:   Can you see that the factories create a binary tree?  The Add to lists button creates a leaf and the Combine! button creates a non-empty binary tree whose children are either leaves or non-empty trees.

 

 

 


© 2010 by Stephen Wong