Categories
frameworks

Growing Frameworks: Patterns

Design patterns are micro-architectures that solve a particular design problem. See the class text Design Patterns. A pattern is a literary form that describes a problem, the forces surrounding it, and a solution that resolves those forces.
 
The designs described here will influence your framework’s structure. They will also be at work in your implementation classes.
 
We will examine several design patterns, and how they’ve been applied in the Java class libraries (mostly AWT and Swing).
 
“Micro-architecture” is meant to convey the idea of a small piece of the total architecture. It may consist of only a couple classes, configured in a way that will solve a particular problem. For example, the Singleton pattern says how to handle classes that should have only one instance:
·         Make the constructor private (so clients can’t create them)
·         Provide a static method getInstance() that returns the single instance.
This only involves the design structure of one class, but it solves the problem at hand. More complicated patterns may address two, three, or several classes, but they don’t try to provide a comprehensive solution to the “whole” problem.
 
Patterns as flex axes [TBD]
 
A solution to a problem can be thought of as representing something in a multi-dimensional space. By making the dimensions independent, we attain greater flexibility in assembling the whole solution. While we study patterns, we’ll look at not only what they are, but what makes them flexible.
 
This is not a comprehensive analysis of patterns. The best reference is still the original book Design Patterns by Gamma et al. Our goal here is to provide enough information to briefly expalin what each pattern does, and relate its flexibility to the needs of frameworks.

Pattern
What It Makes Flexible
Form vs. Function
Factory Method
What is constructed
Structure
Adapter
Support of an interface
Structure
Facade
Complex structure behind a simple interface
Structure
Composite
Containment structure
Structure
Decorator
Cumulative effects
Algorithm
Template Method
Steps of a fixed algorithm
Algorithm
Strategy
Algorithm
Algorithm
Observer
Independence of model from view
? [TBD]
Command
Functions treated as objects
? [TBD]
 
 

Factory Method

 
You don’t always want to expose the details of how an object is constructed. You may not want the user to be aware of the particular construction – maybe you’ll change in the future, maybe you build different object types depending on the circumstances, etc.
 
One way around this is to use a Factory Method: a class responsible for building instances of another class. The factory method is often a static method in a Factory class; usually the method is named createXxx() or makeXxx() or some such to indicate its purpose. Sometimes the factory is the same as the class of the desired object.
 
When the constructed class is the same as the factory, you’ll see a class structure like this:
class Xxx {
            // Factory methods
      public static Xxx makeSomeXxx() { …}
      public static Xxx makeAnotherXxx() { …}
            // Protected constructor
      protected Xxx() { …}                               
            // Public methods
      public void doSomething() { …}
      public int getValue() { …}
}
(Note that the factory method need not return a “real” Xxx; often it will return an instance of a subclass of Xxx.)
 
One example of this is the Border object in Swing. There are many border types – etched, line, titled, etc. There is a BorderFactory object that knows how to return an instance of each.
 
Why this separation? For one thing, borders are mostly constant: once created they can’t be changed. So, the factory can keep track of what it has created. Once it has created the first instance of EtchedBorder, it saves it, and returns the saved value each time one is requested. (The client doesn’t care that it’s not a unique border object.) In this way, we avoid creating many unnecessary objects.
 
Recall that we used a factory method in our graph package. This let us avoid making clients depend on the actual Node and Edge types. Without the factory, we’d have client code like this:
      Node n1 = new SimpleNode();
If we ever wanted to use a different node type, we’d have to find and change every constructor! By using the factory method, our code is like this:
      Graph graph = new SimpleGraph();
      Node n = graph.MakeNode();
We still have to worry about the Graph constructor, but we’ll create many more nodes than graphs, and the nodes are now independent of their type.
 
Use a Factory Method when you want to vary (hide!) the construction of objects.
 
[TBD: returning a specialized subclass]
 

Adapter

 
You have one interface, but you need another. Use an Adapter to translate between them.
 
For example, we might like the user to select an object, and then we’ll do something with the selection. What’s the user selecting from? It could be a list, tree, table, radio-button, etc. We don’t want to commit to a particular choice, so we have this interface:
      public interface ObjectSelectionListener {
            public void objectSelected (ObjectSelectionEvent e);
      }
 
The problem is: list, tree, etc. don’t know this interface – they were written before it even existed! To make a list able to notify us of object selections, we’ll introduce an Adapter. It will be a ListSelectionListener so it can work with Lists, and it will manage ObjectSelectionListeners so it can work with our interface.
 
[TBD – check whether it’s list or ListModel]
 
public class ListToObjectAdapter implements ListSelectionListener {
      protected JList list;
      public ListToObjectAdapter (JList list) {
            this.list = list;
            list.addSelectionListener(this);
      }
      public void valueChanged (ListSelectionEvent e) {
            Event e2 = new ObjectSelectionEvent(list.getSelectedValue());
            // for each listener – send e2
      }
      Vector v = new Vector();
      public void addObjectSelectionListener(ObjectSelectionListener listener)
      {
            v.addElement(listener);
      }
      public void removeObjectSelectionListener(ObjectSelectionListener listener) {
            v.removeElement(listener);
      }
}
               
You might use it like this:
 
      JList list = new JList(listModel);
      ListToObjectAdapter adapter = new ListToObjectAdapter(list);
      ObjectSelectionListener osl = new MyObjectDisplay();
      adapter.add(osl);
 
When an event comes in to the adapter, it broadcasts to its listeners.
 
Use an Adapter when you must match two interfaces that are conceptually related, but physically incompatible.
 

Facade

 
[TBD]

Composite

 
Objects often contain instances of their own class (recursively). When you notice such a structure, you can sometimes make use of the Composite pattern.
 
                Parent                     Containers can contain containers, but eventually get to leaves.
                ^ |      |
                | V      V
   Container            Child
 
The Java AWT hierarchy is like this:
                Component
                ^  ^        ^
                |  ihs     ihs
    Container           Button etc.
 
With Composite, there’s a decision about the containment capabilities: is Component aware of them or not? The original AWT says “Components are not containers.”
 
In the new Swing library, they’ve reversed that decision
                Component
                ^ ^           ^
    Container           Button etc still exist
                ^
   JComponent
                ^
JButton etc
 
The Swing “Jxxx” components are all containers – they inherit from JComponent which inherits from Container.
 
Why the change? It makes some things a little easier. You can “atomize” components more. From the outside, you deal with a JButton as a single entity, but inside it is be composed of its inner area and a border, rather than being monolithic.
 
Use Composite when you have a recursive structure.
 

Decorator

 
Sometimes you have a recursive structure (perhaps a Composite), and you want to attach behavior all through the structure. The Decorator pattern tells how to provide this: make sure each object has a common interface and “wrap” the additional behavior around the original object. Usually the interface is cumulative in some sense.
 
An example in Swing is the border class. (Borders are an extension/replacement of Insets.) For example
                ——-
                matte
                Title
                Line
                                contents
 
There is a type of Border called a CompoundBorder, which layers two borders together (an outer and an inner border). The above example is represented like this:
                Compound Border
                                MatteBorder
                                CompoundBorder
                                                TitledBorder
                                                LineBorder
 
Borders can report their sizes and draw themselves. A CompoundBorder is the same: its size is the sum of the two contained border sizes, and it draws itself by letting the borders draw themselves one inside the other.
 
[TBD: more pure if all borders were compound]
 
Another example is the ScrollPane. In most ways, it acts like a panel containing a component. Drawing is done by drawing scrollbars (if needed) and then letting the the “contained” component draw itself.
 
Use this pattern when you have a recursive structure of objects with compatible interfaces, and behavior that accumulates.
 

Template Method

 
You have an algorithm that is generally useful, but the details are particular to an implementation.
[TBD capsule description]
[TBD example – applet]
 
An example of this is the paint() method used by Component. The Component class has no idea how a particular component will be drawn, but the AWT knows that each will draw itself when paint() is called.
 
                Component
                =======
                paint(Graphics g)
 
                   <>
                    |
                MyComponent
                ==========
                paint(Graphics g)
 
In some other class, there is code like this:
                for each component c
                                if it’s visible
                                    Create a graphics context g
                                    c.paint(g)
                                end if
                end for
 
The idea can apply to a set of methods (rather than just one):
                setup()
                process(Item e)
                cleanup()
 
Use this pattern when the basic algorithm is stable, but the individual steps change.
 

Strategy

 
You may have objects that are stable, but an algorithm that changes.
 
For example, the AWT layout is like this. A container’s contents are separate from their layout. You can swap in a new layout manager without affecting how the contents are built.
 
                Manager
                ======
                arrange() {                                                                             —->    Strategy
                                defer to strategy                                               ABCStrategy   DEFStrategy
                }
 
Another classic example is text layout. Your word processor may have an editing mode (where words are wrapped to fit the screen) and a print preview mode (where word breaks are balanced against page size). This can be implemented as a strategy.
 
Use a strategy when the algorithm changes.
 

Observer

 
One of the best known patterns is the Observer pattern (also known as Model-View-Controller). This pattern decouples the update of a data from its display.
 
Suppose you have a data structure, and one or more displays (e.g., a text editor). When the data structure changes, you’d like to update all displays. If the data structure directly updates the display, there’s a problem: every time a new display is added, the data structure must be changed.
 
The Observer pattern breaks this dependency by splitting the model from its views. The model is coupled to the display only weakly: each display registers with the model to request notification when the model changes. The display gets the notice, and queries the model to figure out what changed.
 
The Observer pattern is embedded in the JDK 1.1 event model. For instance, a Button generates ActionEvent notifications. An ActionListener can register with the button, and when the button is clicked, the listener is notified.
 
                Button                                                                                                                                                                    MyActionListener
                addActionListener (1)                                                                                                         actionPerformed (2)
 
Button b = new Button (“test”);
b.addActionListener (new ActionListener() {
                public void actionPerformed (ActionEvent e) {
                                System.out.println(“Button clicked; event=”+e);
                }
} );
 
Notice that the button has no knowledge of the particulars of a listener: it just knows how to refer to one, and to call its actionPerformed() method.
 
Use this pattern when you need to decouple classes.
 
 

Command

 
Sometimes you need a function to act like an object. The Command pattern addresses this.
 
For example, suppose you want to provide a camera simulator, to show the effect of lens filters. You might want the user to drag filters onto a stack, and then show the effect of the combination. You could use the Command pattern: make the filters be command objects, each one a function on the image’s appearance.
 
In the Swing package, there is support for the Command pattern in the Action class and the undo package. The Action class encapsulates functions and objects. For example, an editor can give you a list of Actions, corresponding to functions such as copy or move-to-end-of-line.
 
The undo package introduces a class UndoableEdit. Each UndoableEdit can be done or undone. These objects can be saved to a list, so undo/redo can work by doing or undoing each of the actions in the list.
 
Use this pattern to make a function work as an object.