CroftSoft /
Library /
Tutorials
Interface Seq
David Wallace Croft
2007 Apr 30 Mon
Abstract.
Interface Seq is introduced as a read-only accessor interface to a sequence
such as an Object array or a List.
Over the last few years the software architecture design for my Java desktop
applications has been leaning toward what might be called message-oriented
programming (MoP). In my version of MoP, the model, view, and controller
(MVC) objects are loosely coupled. The view and controller objects do not
invoke mutator methods on the model directly but instead queue command
messages for later processing during the update phase.
I enforce this architecture by providing the view and controller objects
with just an accessor interface reference to the model. An accessor
interface only provides read-only access to an object; it has no mutator
methods and its accessor methods only return primitives, immutable objects,
or additional accessor interfaces. Since no mutator methods or mutable
objects are provided, all requests by the controller to mutate model state
must be passed as command messages to the outgoing queue.
This gets a bit tricky when you want to provide access to a sequence of
elements such an array or a List, both of which are mutable. A defensive
programming technique which is used to cope with this is to return a copy of
the array or List. This is slightly confusing because it is not immediately
obvious from the method signature that the returned sequence object is a
copy; programmers might modify the returned copy with the mistaken
assumption that this is mutating the original sequence in the model.
Because the calling code can modify the returned copy, it cannot be cached
and a new copy must be created each time the access method is called.
One way to avoid creating a new sequence object each time the access method
is called is to copy the elements to a sequence object provided by the
calling code as a method argument such as an appropriately sized array.
The calling code is then
responsible for caching the copy sequence object and reusing it to prevent
unnecessary object creation. In addition to this usage overhead, it has the
additional disadvantage of requiring that the elements be transferred each
time the access method is called.
Another way to prevent new sequence object creation is to return an
unmodifiable List which provides indirect access to the original List.
When the mutator methods are called on the unmodifiable List or its
Iterator, it throws an unsupported operation exception. I do not like this
technique because I think it is confusing; it is not obvious from the method
signature that the returned List is unmodifiable. Plus, I am one of many
who are of the opinion that an object should support all of the methods
in its implemented interfaces instead of relying upon runtime exceptions to
limit its use.
What is needed then, in my opinion, is an accessor interface which is a true
subset of List, providing just the accessor methods but not the mutator
methods. I recently created interface "Seq" for that purpose. The name is
an abbreviation of sequence object and pronounced as seek, a pun on the fact
that Seq gives you direct access to the elements through the index position.
package com.croftsoft.core.util.seq;
/***********************************************************************
* Read-only access to a sequence such as an Object array or a List.
*
* @since
* 2007-04-29
* @author
* <a href="https://www.croftsoft.com/">David Wallace Croft</a>
***********************************************************************/
public interface Seq<E>
////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
{
public int size ( );
public E get ( int index );
////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
}
Note that if the generic parameter E is an accessor interface or an
immutable object class, the Seq implementation is an accessor interface.
In the following example, CharSequence is a read-only accessor interface
for the mutable StringBuilder.
package com.croftsoft.core.util.seq;
import java.util.LinkedList;
import java.util.List;
/***********************************************************************
* Example implementation of Seq as an accessor interface.
*
* @since
* 2007-04-30
* @author
* <a href="https://www.croftsoft.com/">David Wallace Croft</a>
***********************************************************************/
public final class SeqExample
implements Seq<CharSequence>
////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
{
private final List<StringBuilder> stringBuilderList;
////////////////////////////////////////////////////////////////////////
// static methods
////////////////////////////////////////////////////////////////////////
public static void main ( final String [ ] args )
////////////////////////////////////////////////////////////////////////
{
// Create an implementation and mutate
final SeqExample seqExample = new SeqExample ( args );
seqExample.append ( ".java" );
// Create a read-only accessor interface reference for viewing
final Seq<CharSequence> filenameSeq = seqExample;
final int size = filenameSeq.size ( );
for ( int index = 0; index < size; index++ )
{
final CharSequence charSequence = filenameSeq.get ( index );
System.out.println ( charSequence );
}
}
////////////////////////////////////////////////////////////////////////
// constructor methods
////////////////////////////////////////////////////////////////////////
public SeqExample ( final CharSequence [ ] charSequenceArray )
////////////////////////////////////////////////////////////////////////
{
stringBuilderList = new LinkedList<StringBuilder> ( );
for ( final CharSequence charSequence : charSequenceArray )
{
stringBuilderList.add ( new StringBuilder ( charSequence ) );
}
}
////////////////////////////////////////////////////////////////////////
// accessor interface methods
////////////////////////////////////////////////////////////////////////
public int size ( )
////////////////////////////////////////////////////////////////////////
{
return stringBuilderList.size ( );
}
public CharSequence get ( final int index )
////////////////////////////////////////////////////////////////////////
{
return stringBuilderList.get ( index );
}
////////////////////////////////////////////////////////////////////////
// mutator methods
////////////////////////////////////////////////////////////////////////
public void append ( final CharSequence charSequence )
////////////////////////////////////////////////////////////////////////
{
for ( final StringBuilder stringBuilder : stringBuilderList )
{
stringBuilder.append ( charSequence );
}
}
////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
}
Please also see the related tutorial
Interface Slot.
|