CroftSoft /
Library /
Tutorials
Interface Slot
David Wallace Croft
2007 Jan 28 Sun
In my Java programming, I use queues everywhere these days. It used to be
I would just use them for network messaging. Then I also started using
them for passing messages between threads or ensuring that all requests were
served within the same phase of a loop. Now I also use them to promote
loose coupling between objects, especially the model, view, and controller
(MVC). Instead of a direct method call from one object to another, I have
the calling object append a message to a queue for later processing by the
receiver.
This means that I no longer share object references between the MVC classes.
Instead I now provide queue references. For example, a controller object
will append
requests to modify model state on the model request queue instead of calling
model mutator methods directly. Likewise, a model object will post state
update
events to a view queue instead of calling a listener method on the view
object directly.
I was passing queue references to the constructor methods of these objects
so that they could communicate with each other. It occurred to me that I
was providing too much access to the objects that needed a queue reference
simply to send messages, not to receive them. For the same reason that I
created the read-only accessor interface, I wanted to create a write-only
message sending interface.
I decided to call it Slot
after a mail slot that you might
see embedded
in the wall of a post office. With a mail slot, you can only insert
messages; you cannot look to see what else has been inserted or withdraw
messages.
There is really just one type of interaction that you can have with a mail
slot.
Another feature of a mail slot is that you generally have no idea how your
message will be processed on the other side. It could be received by the
intended recipient immediately; it
could be stored for later reading; it could be relayed; it could be copied
and broadcast to multiple recipients; it could be discarded unread.
Assuming you believe in the benefits of abstraction, you simply trust
that the right sort of thing will happen once you let go of your message and
let it slip into the system.
The following is what this simple interface looks like. You can see that I
am only exposing the
offer()
method from interface
java.util.Queue
.
package com.croftsoft.core.role;
/***********************************************************************
* Mail slot for receiving messages to be processed, stored, or relayed.
*
* @since
* 2007-01-28
* @author
* <a href="https://www.croftsoft.com/">David Wallace Croft</a>
***********************************************************************/
public interface Slot<E>
////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
{
public boolean offer ( E e );
////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
}
Here is how you might create an instance of Slot
using an
anonymous inner class as an adapter:
final Queue<Request> requestQueue = new LinkedList<Request> ( );
final Slot<Request> requestSlot = new Slot<Request> ( )
{
public boolean offer ( final Request request )
{
return requestQueue.offer ( request );
}
};
final Requester requester = new Requester ( requestSlot );
final Server server = Server ( requestQueue );
The interface Slot
reference is passed as a constructor method
argument to the Requester
and will probably be stored as a
final instance variable. Using this layer of indirection
obviates the chicken-and-egg problem of passing references as constructor
arguments when each object needs a reference to the other but one must be
instantiated first.
If you see a constructor argument that accepts a Queue
as an
argument, you might have to read further to see how it is used, whether
for sending, receiving, or both sending and receiving messages.
This is not so with an argument of type Slot
.
Note that class Server
receives a direct reference to an
instance of interface Queue
via its constructor method since it
must be able to call the poll()
method in order to process the
requests. Perhaps a simpler interface with just that method is all it
needs. If so, the interface might be called Pollable
or
something a bit shorter.