Evaluating Software Design Patterns
— the "Gang of Four" patterns implemented in Java 6

dk.rode.thesis.observer
Class BirthdayRegistry

java.lang.Object
  extended by dk.rode.thesis.observer.BirthdayRegistry

@Participant(value="ConcreteObserver")
public class BirthdayRegistry
extends Object

A birthday registry is a simple application that stores the name and date of birth of people registered to it.

Once a given date is reached in a given ObservableSequence<SequenceObserver,Date>, the associated names will be listed according to the current date received from the sequence in question.

Birthdays can be supplied as strings that will be parsed into actual dates based on a date format supplied at construction time, or supplied directly as Date objects.

A birthday registry is not thread-safe!

Usage:

    // Create...
    DateFormat df = new SimpleDateFormat("dd-MM-yyyy");
    BirthdayRegistry br = new BirthdayRegistry(df);
    
    // Add birthday and associated name - only date, month,
    // and year are used, regardless of date format used...
    br.add("08-01-1942", "Stephen Hawking");
    br.add("07-08-1885", "Niels Bohr");
    ..
    
    // The registry does not flaunt that it is an observer, but uses an
    // inner class to implement observer functionality that simply 
    // invokes the proper private method in the registry. Any observable 
    // sequence delivering dates and using the SequenceObserver
    // interface can be utilised...
    DateSequence ds1 = new DateSequence();
    AspectObservableSequence<SequenceObserver,State,Date> ds2 = ..
    
    // Register only on NORMAL and RESET state...
    State next  = Sequence.State.NORMAL,
          reset = Sequence.State.RESET;
    br.register(ds1, next, reset); // varargs
    // Register for all states...
    br.register(ds2);
    
    // Will not be added twice...
    br.register(ds2);
 
Implementation notes:
This registry uses an inner class to implement the observer functionality, which ensures that we do not expose the observer interface for misuse. This is common practice in Java. However, since the inner class is in effect an adapter, the exact type of notification mechanism used by the observable sequence must be known. Here, the SequenceObserver interface is used, and this limits the type of applicable observable sequences to SequenceObserver<SequenceObserver,Date>.

Author:
Gunni Rode / rode.dk

Nested Class Summary
private  class BirthdayRegistry.RegistryObserver<A>
          A registry observer forwards call to the enclosing registry.
 
Field Summary
private  Map<String,Date> birthdays
          The map storing the birthdays: (key, value) = (name,birthday) = (String,Date)
private  DateFormat dateFormat
          The date format used to parse string date representations into actual dates.
 
Constructor Summary
BirthdayRegistry(BirthdayRegistry registry)
          Copy constructor.
BirthdayRegistry(DateFormat dateFormat)
          Constructor.
 
Method Summary
 boolean add(Date birthday, String name)
          Associates the person having the name and birthday supplied as name and birthday, respectively, with this registry.
 boolean add(String birthday, String name)
          Associates the person having the name and birthday supplied as name and birthday, respectively, with this registry.
private  void checkDate(Date date)
          Actual observer method that lists the names of persons registered in this registry that were born on date, if any.
 Map<String,Date> getAll()
          Returns a map containing all the registered names and associated birthdays.
private static Date getBirthday(Date birthday)
          Normalises the date supplied as birthday to only include day and month.
 Date getBirthday(String name)
          Returns the full birthday of the person having the name supplied as name, if registered.
private static Date getFullBirthday(Date birthday)
          Normalises the date supplied as birthday to only include day, month, and year.
private static String getName(String name)
          Normalises the name supplied as name to be trimmed, and each unique part of the name separated by a single space is upper-cased first.
 List<String> getNames(Date birthday, boolean full)
          Returns a collection of names associated with the birthday supplied as birthday.
 List<String> getNames(String birthday, boolean full)
          Returns a collection of names associated with the birthday supplied as birthday.
<A> boolean
register(AspectObservableSequence<SequenceObserver<A>,A,Date> sequence, A... aspects)
          Registers this registry as an observer for the observable sequence supplied as sequence, if not already.
<A> boolean
register(ObservableSequence<SequenceObserver<A>,A,Date> sequence)
          Registers this registry as an observer for the observable sequence supplied as sequence, if not already.
 int size()
          Returns the number of birthday dates, not people, registered in this registry.
 String toString()
          Returns the string representation of this registry.
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait
 

Field Detail

birthdays

private final Map<String,Date> birthdays
The map storing the birthdays:
   (key, value) = (name,birthday) = (String,Date) 
 


dateFormat

private final DateFormat dateFormat
The date format used to parse string date representations into actual dates.

Never null.

Constructor Detail

BirthdayRegistry

public BirthdayRegistry(BirthdayRegistry registry)
Copy constructor.

Parameters:
registry - The registry to copy; cannot be null.
Throws:
NullPointerException - If registry is null.

BirthdayRegistry

public BirthdayRegistry(DateFormat dateFormat)
Constructor.

Parameters:
dateFormat - The format used to parse string representations of dates; cannot be null.
Throws:
NullPointerException - If dateFormat is null.
Method Detail

add

public boolean add(Date birthday,
                   String name)
Associates the person having the name and birthday supplied as name and birthday, respectively, with this registry.

An existing registration on name will be overwritten.

Parameters:
birthday - The birthday; cannot be null.
name - The name; cannot be null, or empty.
Returns:
True if this registration overwrites an existing one, false if not.
Throws:
NullPointerException - If either argument is null.
IllegalArgumentException - If name is empty.

add

public boolean add(String birthday,
                   String name)
            throws ParseException
Associates the person having the name and birthday supplied as name and birthday, respectively, with this registry.

An existing registration on name will be overwritten.

Parameters:
birthday - The birthday; cannot be null.
name - The name; cannot be null, or empty.
Returns:
True if this registration overwrites an existing one, false if not.
Throws:
NullPointerException - If either argument is null.
IllegalArgumentException - If name is empty.
ParseException - If birthday has an illegal format.

checkDate

private void checkDate(Date date)
Actual observer method that lists the names of persons registered in this registry that were born on date, if any.

Invariant: date is a full birthday date.

Parameters:
date - The date; never null.
See Also:
register(AspectObservableSequence, Object...)

getAll

public Map<String,Date> getAll()
Returns a map containing all the registered names and associated birthdays.

Modifying the returned map will not affect this registry.

Returns:
The map; never null, but may be empty.

getBirthday

private static final Date getBirthday(Date birthday)
Normalises the date supplied as birthday to only include day and month.

Parameters:
birthday - The birthday to normalise; cannot be null.
Returns:
A new normalised date; never null.
Throws:
NullPointerException - If birthday is null.

getBirthday

public Date getBirthday(String name)
Returns the full birthday of the person having the name supplied as name, if registered.

Parameters:
name - The name; cannot be null, or empty.
Returns:
The birthday, or null if not registered.
Throws:
NullPointerException - If name is null.
IllegalArgumentException - If name is empty.

getFullBirthday

private static final Date getFullBirthday(Date birthday)
Normalises the date supplied as birthday to only include day, month, and year.

Parameters:
birthday - The birthday to normalise; cannot be null.
Returns:
A new normalised date; never null.
Throws:
NullPointerException - If birthday is null.

getName

private static final String getName(String name)
Normalises the name supplied as name to be trimmed, and each unique part of the name separated by a single space is upper-cased first.

Parameters:
name - The name to normalise; cannot be null.
Returns:
A new normalised name; never null.
Throws:
NullPointerException - If name is null.
IllegalArgumentException - If name is empty.

getNames

public List<String> getNames(Date birthday,
                             boolean full)
Returns a collection of names associated with the birthday supplied as birthday.

Modifying the returned collection will not affect this registry.

Parameters:
birthday - The birthday; cannot be null.
full - If true, the birthday must match on day, month, and year; if false, only on day and month.
Returns:
A list of names; never null, but can be empty.
Throws:
NullPointerException - If birthday is null.

getNames

public List<String> getNames(String birthday,
                             boolean full)
                      throws ParseException
Returns a collection of names associated with the birthday supplied as birthday.

Modifying the returned collection will not affect this registry.

Parameters:
birthday - The birthday; cannot be null.
full - If true, the birthday must match on day, month, and year; if false, only on day and month.
Returns:
A list of names; never null, but can be empty.
Throws:
NullPointerException - If birthday is null.
ParseException - If birthday has an illegal format.

register

public <A> boolean register(AspectObservableSequence<SequenceObserver<A>,A,Date> sequence,
                            A... aspects)
Registers this registry as an observer for the observable sequence supplied as sequence, if not already.

Type Parameters:
A - The type of aspect; ignored by this registry.
Parameters:
sequence - The sequence; cannot be null.
aspects - The aspects to subscribe to; can be or contain null, i.e. all events.
Returns:
True if this registry was added as an observer, false if not.
Throws:
NullPointerException - If sequence is null.

register

public <A> boolean register(ObservableSequence<SequenceObserver<A>,A,Date> sequence)
Registers this registry as an observer for the observable sequence supplied as sequence, if not already.

Type Parameters:
A - The type of aspect; ignored by this registry.
Parameters:
sequence - The sequence; cannot be null.
Returns:
True if this registry was added as an observer, false if not.
Throws:
NullPointerException - If sequence is null.

size

public int size()
Returns the number of birthday dates, not people, registered in this registry.

Returns:
The number of birthday dates.

toString

public String toString()
Returns the string representation of this registry.

Overrides:
toString in class Object
Returns:
The string representation; never null.

Gunni Rode / rode.dk

Feel free to use and/or modify the Java 6 source code developed for this thesis AT YOUR OWN RISK, but note that the source code comes WITHOUT ANY — and I do mean WITHOUT ANY — form of warranty WHAT SO EVER!

The original thesis and source code are available at rode.dk/thesis.