CSC

 

Lab 4 - Design patterns

Design patterns describe reccurring solutions to common problems in object-oriented programming. Using the patterns, problems will be solved faster and safer than without them. Some patterns are simple while others are fairly complicated.

When you learn a new pattern, in order to really understand it, it is a good idea to first write a "toy program" using the pattern, i.e. a programme with the sole purpose to demonstrate the pattern and understand it fully.

In this lab assignment you will write "toy programs" for two or three common and popular patterns.

Pattern Composite

The idea with Composite is that groups of objects, arranged in a hierarchy, may be handled in the same way as single objects. A composite object contains other objects which can be composite or single. One example of a Composite structure is a file directory which can contain files and other directories (which can contain files and directories ...). The single files are the leaves of the tree structure. Another example of a Composite structure is a picture built from graphic primitives and groups of primitives. A group may consist of primitives and groups. A classical example of Composite can be found in the Java API: The classes Component, Container and their subclasses. A Container inherits from Component but can contain any number of Components who themselves can be Containers or "leaf"-Components (e.g. Labels or Buttons).

A nice introduction to the Composite pattern can be found here: www.dofactory.com/Patterns/PatternComposite.asp

Assignment part 1 - Suitcase as Composite

When packing a suitcase, you can make use of the Composite pattern. Sweaters and trousers will be placed directly in the suitcase whereas tiny items such as braids or hair pins will be placed in small boxes or bags which in turn may be placed in a toilet bag and packed next to the larger single things in the suitcase. Socks could be put in a plastic or nylon bag which is put in the suitcase.

Implement the necessary classes for a suitcase according to the Composite pattern. The class called Component in the description of the pattern is a base class (possibly abstract) from which the classes for the single items as well as the classes for composite items inherit. Use the classes in a test program to build a suitcase following the Composite pattern.

At least 10 different items (e.g. sweater, jeans, sock, T-shirt, bracelet, pen ... use your imagination!) of at least five different categories must be paced in the suitcase. At least three different levels of composites must be used (e.g. hairpins are in a small plastic bag along with soap and shampoo in a toilet bag and the toilet bag is in the suitcase with larger garments).

It is OK to use one single class for all the single items and separate them with just a String attribute. Also for the composites you may use the same class for all or define one class for ToiletBag, one for Suitcase, one for PlasticBag etc.

Each object must have attributes (instance variables) price and weight. The attributes should be assigned values through a standard constructor when the objects are created. There must be two operations (Operation() in the general description of the pattern): price() and weight() that will return the corresponding data or computed value for the objects. Each composite should contain a list of its contents (implemented e.g. as an ArrayList) and the methods price() and weight() must return the total price and weight of the composite object. In the test program, the toal value (price) and weight of the suitcase must be calculated with a method call similar to suitcase.weight(). Please note that the suitcase itself and bags have price and weight which must be added to the price and weight of their contents in order to get the correct total weight and total price of the suitcase.

Please also note that you must not write any recursive methods! The recursive structure of the pattern makes it possible to visit all the nodes of the composite structure by only using simple loops in the methods price() and weight().

Factory technique

A number of design patterns have the word factory in their names. What they have in common is that objects are not created in the ordinary way, using new, but with a method call. The methods that create objects are considered to be "factories" (inside the methods the operator new will be used). Common names for such methods are getInstance() or create(). The type of the created object is often determined in the method, out of reach for the user who only knows a supertype (the return type of the method he/she uses). Common reasons for using this technique are 1) to make the programming task easier for the user, an object of the correct type and with the desired properties is "automatically" delivered and 2) it is safer if the type of object is determined by the tested method and not by the user who could easily make a mistake and choose the wrong type.

Assignment part 2 - Human Factory

Implement an abstract class Human with two concrete subclasses Man and Woman. The class Human must have a factory-method:
    public static Human create (String pnr) {
        // method body
    }
We assume that the parameter given when calling this method is a correct swedish social security number (your program does not have to check this). If the last character but one is an odd digit, an object of subclass Man is returned, if it is an even digit, an object of subclass Woman is returned.

Write a test program that creates objects of Man and Woman using the method above. Make sure that it is not possible to create objects of Man and Woman in any other way than with the method create(...). Accordingly, the code new Man(...) and new Woman(...) must give compilations errors in the test program. Attempts to create an objects of anonymous subclasses of Human should also be rejected.

Hints: One way (is it the only way?) to solve the task is to make a package human where you put the class Human and its subclasses. Put the files of the package in a directory with the same name as the package. With the use of suitable modifiers (public, protected, private) on classes and methods in the package, the requested structure can be achieved. Put the test program at the directory level above the package (and not in the package itself). Make sure that the created objects somehow confirm their types. For example:

    :
    Human anna = Human.create("Anna", "xxxxxx-012x");
    Human magnus = Human.create("Magnus","xxxxxx-011x");
    System.out.println(anna);
    System.out.println(magnus);
kan ge utskriften
    I am a woman and my name is Anna
    I am a man and my name is Magnus

Lab demonstration and program requirements

  • Run the test program for Composite where total price and total weight of the suitcase (or other Composite object of your choice) are printed.
  • Show the UML class diagram for the program.
  • Show an object diagram of your Composite structure. It is not necessary that it follows the UML standard, just draw your object structure in a comprehensible way.

  • Run the Human factory program where at least one Man and one Woman are created.
  • Demonstrate another version of the test program where compilation of new Man(...) and new Woman(...) fail.

Extra assignment - the Iterator pattern

The purpose ot the Iterator pattern is to iterate over or "walk through" all the elements of a compound structure without exposing its underlying representation. The use of iterators on list structures is obvious and the implementation is fairly straightforward.

However, also on a Composite (object following the Composite pattern) or other tree structure, an iterator can be very useful. The iterator "delivers" the elements in a sequential manner. For some applications, an arbitrary order is fine, while others may need a specified order, e.g. pre-, post- or in-order when the structure is a tree.

The iterator pattern is described here:
www.dofactory.com/Patterns/PatternIterator.asp

Extra assignment - Two iterators on the Composite

The task of the extra assignment is to implement two iterators on the Composite strucure from the first part of this assignment. The two iterators must give the elements in preorder and Breadth-First-order respectively. Preorder means that any root element is followed by the elements (in preorder) of all its subtrees from left to right. Breadth-first-order means that after the root come all the nodes which are the children of the root and thereafter all the grandchildren of the root etc.

The iterators should implement an interface similar to

interface Iterator {
    Object first();       // return first element
    Object next();        // move one step forward and return the next element 
    boolean isDone();     // return true when all elements are visited
    Object currentItem(); // return the current item without moving forward
}
Write two classes that implement this interface, one for preorder and one for breadth-first on the Composite structure. All accessing of the elements of the composite must be done in the concrete iterator classes. Therefore, the composite should be passed as a parameter to the iterator classes' constructors.

Creation of the iterators is done in the Composite class which should be extended with one factory method similar to

    Iterator getIterator (String s) {
        if (s.equals("PO"))
            return new POIterator(this); //Preorder-iterator
        else
            return new BFIterator(this); //Breadth-first-iterator
    }
The method getIterator is the only change/extension that is allowed in the original Composite classes! Extensions that are natural parts of or complements of the original structure are allowed, e.g. toString-methods.

You may assume that the Composite objekt remains stable during the iteration, i.e. no objects are added to or removed from the Composite. If the Composite is changed during iteration, the iterator may show the Composite at the time of the iterators creation.

Lab demonstration

Testing of the new iterators can be done in the same program as the testing of the composite itself. Create the iterators and iterate each of them over all the elements. Print the elements to establish that they appear in the expected order.
Published by:<ann "at"nada.kth.se>
Updated: april 11, 2010
Support:<webmaster@nada.kth.se>