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.

 
 
 
CroftSoft
 
 
About
Library
-Books
-Code
-Courses
-Links
-Media
-Software
-Tutorials
People
Portfolio
Update
 
 
Google
CroftSoft Web

 

Creative Commons License
© 2007 CroftSoft Inc.
You may copy this webpage under the terms of the
Creative Commons Attribution License.