|
Evaluating Software Design Patterns — the "Gang of Four" patterns implemented in Java 6 |
||||||||
PREV CLASS NEXT CLASS | FRAMES NO FRAMES | ||||||||
SUMMARY: NESTED | FIELD | CONSTR | METHOD | DETAIL: FIELD | CONSTR | METHOD |
java.lang.Object dk.rode.thesis.meta.model.AbstractSequence<E> dk.rode.thesis.templatemethod.SequenceTemplate<K,E>
K
- The type of correlation keys used by this sequence. Use
Void
if not used.E
- The type of values delivered by this sequence.@Participant(value="AbstractClass") public abstract class SequenceTemplate<K,E>
A sequence template forms a template for sequences requiring several steps to construct, deliver, and dispose sequence values. An example could be values fetched from a database that requires steps like open connection, begin transaction, fetch value, end transaction, and close connection.
Sub-class implementation:
The basic sequence methods current()
, next()
,
and reset()
as well as close()
are declared
final - they are template methods. Instead, a sequence
template defines the following (abstract) primitive operations
that can or must be implemented, i.e. if abstract, in
sub-class implementations:
sequenceOpen(Object...)
: performs initialisation of
this sequence before any sequence values are delivered ("open
connection"). Is invoked upon construction
of new sequences and
copying
of
existing sequences when needed. Sub-class constructors should therefore
not perform initialisation. Must be implemented.
sequenceReset()
: resets this sequence for reuse when
this sequence is restarted or reset
("close and
re-open connection"). Default implementation does nothing.
sequenceClose()
: closes this sequence after use, so no more
sequence values can be delivered by this sequence ("close connection").
Once this sequence has been closed, trying to acquire sequence values
from it will cause an exception
to
be thrown. Default implementation does nothing. Is invoked
when sequences are closed
.
next()
are
created in three steps:
nextValueOpen(E)
: prepares the next
sequence value to be delivered ("begin transaction"). The
argument supplied is the current (previous)
sequence value and the returned value is a correlation key used
to identify the value to sub-sequence calls to
nextValue(K, E)
and
nextValueClose(K, E)
methods for the same value. If no correlation key is used, simply
return null. Must be implemented.
nextValue(K, E)
: fetches or constructs the
actual sequence value to be delivered as the next value, or returns null if
this sequence has no more values ("fetch value"). The type of value
is determined by the type parameter E
. The first supplied argument
is the correlation key returned by the nextValueOpen(E)
method, and the second the current (previous) value.
Must be implemented.
nextValueClose(K, E)
: finalises the
sequence value just constructed with nextValue(K, E)
("end transaction"). The supplied arguments are in
order the correlation key generated by nextValueOpen(E)
and the actual sequence value generated by
nextValue(K, E)
. Default implementation
does nothing.
next
sequence value,
the functionality of a sequence template is thus:
// current = old value E current = this.As default, sequence templates are declared ascurrent()
; // Open and get correlation key... K key =nextValueOpen(current)
; // Get actual value based on correlation key and *old* value... value =nextValue(key, current)
; // Close newly created value (e.g. resources)...nextValueClose(key, value)
; // Update current... this.current = value; return value;
bounded
,
consistent
, and unique
, but sub-classes
should override this behaviour as appropriate.
Implementation notes:
All attributes are declared private in this class to prevent sub-classes
from modifying them outside the scope of the (abstract) operations.
Java makes it easy for sub-classes to determine which (abstract) operations
must be implemented: those declared abstract. Furthermore, to ensure that
the template methods are not overridden, they should be declared final. This
also gives the sub-class implementer a clear view of which methods can
be overridden. Gamma et al. also emphasise the need for consistent
naming among (abstract) operations for clarity [Gamma95, p.329]. Here,
all operations related to overall sequence functionality are prefixed with
sequence
, and operations related to generating the next value with
nextValue
. The last part of the names of the (abstract) operations
determine their functionality, e.g. Open
and Close
as in nextValueOpen
and nextValueClose
.
As described above, the initialisation of sub-class sequence implementations
is performed using the sequenceOpen(Object...)
method, invoked
automatically via the constructors defined in this class when
needed. Sub-class constructors must invoke one of these constructors, but will
declare explicit arguments types as needed to create the specific type of
sequence. They will thus pass matching arguments to the super-constructor, which then
invokes the sequenceOpen(Object...)
initialisation method. However, casts
are still required in the method implementation, but are known to succeed since the
arguments originate from one of the parameter type-safe constructors in the same
class. This is in our view a very elegant use of varargs. An alternative could
be to use an additional generic type parameter on this class, say P
, to
narrow the argument type(s) for the constructors and the sequenceOpen(Object...)
method (and thus in sub-classes overriding it) even further, e.g.
sequenceOpen(P...)
. But, if more than one argument is needed with
different type hierarchies, the actual type parameter for P
would still
need to be Object
, so the question is how much will be gained?! Here, no
such type parameter is used.
Nested Class Summary |
---|
Nested classes/interfaces inherited from interface dk.rode.thesis.meta.model.Sequence |
---|
Sequence.State |
Field Summary | |
---|---|
private boolean |
closed
True if this sequence has been closed . |
private E |
current
The current sequence value. |
private int |
index
The current index into this sequence, used to calculate the size of this sequence. |
protected static SequencePolicy |
POLICY
Policy use for logging of this sequence. |
private int |
size
The size of this sequence, i.e. the number of values delivered. |
Fields inherited from class dk.rode.thesis.meta.model.AbstractSequence |
---|
state |
Constructor Summary | |
---|---|
protected |
SequenceTemplate(Object... arguments)
Constructor, which creates this sequence template. |
protected |
SequenceTemplate(SequenceTemplate<K,E> sequence,
Object... arguments)
Copy constructor, which creates this sequence template based on sequence , i.e. to have the same size, use the same
current index, etc. |
Method Summary | |
---|---|
boolean |
bounded()
Returns true if this sequence is bounded, i.e. |
void |
close()
Closes this sequence. |
boolean |
consistent()
Returns true if this sequence is consistent, i.e. deliver the same values, in order, after restart or reset . |
E |
current()
Returns the current element from this sequence. |
protected void |
ensureOpen()
Guard method that will throw an exception
if this sequence is not open, or otherwise return silently. |
protected void |
finalize()
Simply invokes close() . |
protected int |
index()
Returns the index of the current sequence value in this sequence. |
boolean |
isClosed()
Returns true if this sequence has been closed ,
false if not. |
E |
next()
Returns the next element from this sequence. |
protected abstract E |
nextValue(K key,
E current)
This abstract operation creates the next sequence
value to be delivered. |
protected void |
nextValueClose(K key,
E value)
Ensures that this sequence finalises the sequence value just created, if required. |
protected abstract K |
nextValueOpen(E current)
Prepares this sequence for the next sequence value to
be delivered based on the current value supplied
as current . |
void |
reset()
Resets this sequence to start over if it is consistent. |
protected void |
sequenceClose()
Performs sub-class specific procedures for closing
this sequence. |
protected abstract boolean |
sequenceOpen(Object... arguments)
Performs sub-class specific initialisation of this sequence before sequence values will be delivered, and returns true upon success. |
protected void |
sequenceReset()
Performs sub-class specific reset of this
sequence before sequence values will be delivered. |
int |
size()
Returns the number of sequence elements in this sequence. |
boolean |
unique()
Returns true if this sequence deliver a given sequence value at most one time until reset or restarted. |
Methods inherited from class dk.rode.thesis.meta.model.AbstractSequence |
---|
getStringablePolicy, state, toString, toString |
Methods inherited from class java.lang.Object |
---|
clone, equals, getClass, hashCode, notify, notifyAll, wait, wait, wait |
Methods inherited from interface dk.rode.thesis.meta.model.Sequence |
---|
copy |
Field Detail |
---|
private boolean closed
closed
. If so, no more
values can be delivered by this sequence.
private E current
Never null.
private int index
Interval: 0 <= index <= size
(once size has been calculated).
protected static final SequencePolicy POLICY
Change at compile time for more verbose output.
private int size
Calculated once this sequence has restarted.
Initialised to Const.INFINITE
.
Constructor Detail |
---|
protected SequenceTemplate(Object... arguments) throws SequenceValueException
The initialisation
of
this sequence is performed with arguments
as arguments.
arguments
- The arguments, if any, to use in the
initialisation of this sequence; can be null.
SequenceValueException
- If the initialisation fails, or if the
initial current value of this sequence cannot be fetched.protected SequenceTemplate(SequenceTemplate<K,E> sequence, Object... arguments) throws SequenceValueException
sequence
, i.e. to have the same size, use the same
current index, etc.
Initialisation of this sequence template is still performed unless
sequence
is closed
. The
initialisation
is thus performed with
arguments
as arguments. Alternatively, if sequence
is closed, this sequence will be closed as well.
sequence
- The sequence to copy; cannot be null.arguments
- The arguments, if any, to use in the
initialisation of this sequence; can be null.
NullPointerException
- If sequence
is null.
SequenceValueException
- If the initialisation fails.SequenceTemplate(Object...)
Method Detail |
---|
public boolean bounded()
Sequence
The same type of sequence may represent both bounded and
unbounded sequences and the behaviour is determined and fixed
at construction time.
Bounded sequences will restart if they deliver
consistent
values.
bounded
in interface Sequence<E>
Sequence.unique()
public final void close()
Once this sequence has been closed
, sequence values
can no longer be delivered.
The context should always remember to close a sequence template to ensure that it proper finalisation is made.
Closing this sequence twice has no effect.
close
in interface Closeable
sequenceClose()
public boolean consistent()
Sequence
reset
.
Only bounded
consistent sequences will restart.
Consistent sequences need not deliver unique
sequence values.
Instances of the same type of sequences are always consistent or inconsistent; it is determined at design time, not construction time.
consistent
in interface Sequence<E>
public final E current()
Sequence
This method can be invoked even if Sequence.next()
has not been invoked yet, thus delivering the initial
value of this sequence.
current
in interface Sequence<E>
SequenceValueException
- If this sequence has been
closed
.protected final void ensureOpen()
exception
if this sequence is not open, or otherwise return silently.
protected final void finalize() throws Throwable
close()
.
finalize
in class Object
Throwable
- If the finalising fails.protected final int index()
public final boolean isClosed()
closed
,
false if not.
A closed sequence cannot deliver sequence values, and trying to
do so will cause a exception
to
be thrown.
ensureOpen()
public final E next()
Sequence
next
in interface Sequence<E>
SequenceValueException
- If this sequence has been
closed
, or if the next value cannot
be fetched.nextValueOpen(E)
,
nextValue(K, E)
,
nextValueClose(K, E)
protected abstract E nextValue(K key, E current) throws Exception
next
sequence
value to be delivered. This is step 2/3 in value creation, where
the previous step was nextValueOpen(E)
and the last is nextValueClose(K, E)
.
key
- The correlation key just created by
nextValueOpen(E)
; can be null.current
- The current (soon to be previous) sequence value; never null
unless initialising this sequence (once).
next()
returns; null means sequence restart,
which is only allowed if this sequence is bounded
.
Exception
- In case value construction fails.protected void nextValueClose(K key, E value) throws Exception
nextValueOpen(E)
and
nextValue(K, E)
. Default implementation does nothing.
key
- The correlation key just created by
nextValueOpen(E)
;
can be null.value
- The sequence value just created by
nextValue(K, E)
; never null.
Exception
- In case the closing fails; not thrown by the
default implementationprotected abstract K nextValueOpen(E current) throws Exception
next
sequence value to
be delivered based on the current
value supplied
as current
. This is step 1/3 in value creation, where
the next steps are nextValue(K, E)
and
nextValueClose(K, E)
.
The returned correlation key will be used to identify the
same creation process in subsequent calls to nextValue
and nextValueClose
.
current
- The current (soon to be previous) sequence value; never null
unless initialising this sequence (once).
Exception
- In case the opening fails.public final void reset()
Sequence
If this sequence is consistent
, the
sequence will restart.
reset
in interface Sequence<E>
reset
in class AbstractSequence<E>
SequenceValueException
- If this sequence has been
closed
, or if the reset fails
otherwise.sequenceReset()
protected void sequenceClose() throws Exception
closing
this sequence. Once this sequence is closed, sequence values can
no longer be delivered. Default implementation does nothing.
Exception
- Not thrown by the default implementation.sequenceReset()
,
sequenceOpen(Object...)
protected abstract boolean sequenceOpen(Object... arguments) throws Exception
closed
.
Initialisation is performed upon construction
of new sequences and when
copying
existing
sequences, if needed. The arguments supplied to this (abstract) operation
is the varargs arguments supplied at construction time (e.g. via sub-class
implementations).
arguments
- Arguments required by the initialisation, if any;
never null, but can be empty.
Exception
- If the initialisation fails.sequenceReset()
,
sequenceClose()
protected void sequenceReset() throws Exception
reset
of this
sequence before sequence values will be delivered. Default implementation does nothing.
Exception
- Not thrown by the default implementation.sequenceOpen(Object...)
,
sequenceClose()
public final int size()
The size is not calculated until this sequence has restarted.
Until then, a value of Const.INFINITE
is returned.
INFINITE
if not calculated yet.public boolean unique()
Sequence
reset
or restarted.
Unbounded
sequences that are unique will never
deliver the same sequence value more than once.
The same type of sequence may represent both unique and not unique sequences and the behaviour is determined and fixed at construction time.
unique
in interface Sequence<E>
Sequence.consistent()
|
Gunni Rode / rode.dk | ||||||||
PREV CLASS NEXT CLASS | FRAMES NO FRAMES | ||||||||
SUMMARY: NESTED | FIELD | CONSTR | METHOD | DETAIL: FIELD | CONSTR | METHOD |