Best interface design?

A

Adam

VisionSet said:
Consider an object that needs to be accessible over a network, and also
locally. Which do you think is the best design:

1/ Have one interface that declares RemoteExceptions and any other
Exceptions peculiar to the Object. Disadv: The object will never throw a
RemoteException if available locally.

2/ Have two interfaces almost identical except one throws the
RemoteExceptions in addition. Disadv: two interfaces to maintain that must
mirror each other.

I like the 2nd idea:

interface ForRemoteUse
{
void aMethod() throws RemoteException;
}

interface ForLocalUse extends ForRemoteUse
{
void aMethodNoExceptions();
}

class RemoteImplementation implements ForRemoteUse
{
void aMethod throws RemoteException
{
//code
}
}

class LocalImplementation extends RemoteImplementation implements
ForLocalUse
{
void aMethodNoException()
{
try{
aMethod();
}catch(RemoteException e)
{
throw new Error("Local implementation was supposed not to
throw RemoteException at all!!!");
}
}
}

Check out EJBs (remote, local and home interfaces) - i think they are
dealing with the same thing there.

Adam
 
V

VisionSet

Consider an object that needs to be accessible over a network, and also
locally. Which do you think is the best design:

1/ Have one interface that declares RemoteExceptions and any other
Exceptions peculiar to the Object. Disadv: The object will never throw a
RemoteException if available locally.

2/ Have two interfaces almost identical except one throws the
RemoteExceptions in addition. Disadv: two interfaces to maintain that must
mirror each other.
 
M

Michael Borgwardt

VisionSet said:
Consider an object that needs to be accessible over a network, and also
locally. Which do you think is the best design:

1/ Have one interface that declares RemoteExceptions and any other
Exceptions peculiar to the Object. Disadv: The object will never throw a
RemoteException if available locally.

2/ Have two interfaces almost identical except one throws the
RemoteExceptions in addition. Disadv: two interfaces to maintain that must
mirror each other.

The second is rather pointless, as it takes away the only reason to have
an interface at all: to refer only to the interface type in the rest
of the application.
 
V

VisionSet

Michael Borgwardt said:
The second is rather pointless, as it takes away the only reason to have
an interface at all: to refer only to the interface type in the rest
of the application.

Okay, I agree my designs above are brief.

2/ ... A wrapper takes an instance of the remote interface version and wraps
it to provide an implementation of the local interface. Thus providing one
type in two flavours.

I am totally split on 1/ & 2/ is there an ideal /3 ?
 
C

Chris Uppal

VisionSet said:
Consider an object that needs to be accessible over a network, and also
locally. Which do you think is the best design:

1/ Have one interface that declares RemoteExceptions and [...]
2/ Have two interfaces almost identical [...]

If you are intending/expecting that you might be using the objects in both
local and remote configuration more-of-less interchangeably, then clearly you
have to go for (1). E.g. if you have a GUI for editing/displaying them, and
you don't want to maintain two almost identical code-bases for two almost
identical editors (and who would ?), then the editor has to be able to cope
with all the failure modes exhibited by the objects in either configuration.
This applies even if the overall applications don't allow interchangeable use
of local or remote objects, provided they share a reasonable amount of code
that is aware of the objects but is not configuration-specific.

That seems the most likely situation to me, but maybe it doesn't apply in your
case. If so then (by hypothesis) you have a situation where you have two
independent applications (no significant overlap in code, and presumably not in
function either). In this case the application code will be talking about
different things, and talking in different ways (if only because the failure
modes are different), and there seems to be no obvious reason why the two
interfaces should be the same -- any similarity would seem to be a kind of
accident. That invites the question of why one object is fulfilling two such
different roles, but leaving that aside it still seems that maintaining
consistency between the two interfaces would not be a problem --
simply because there is no /need/ for consistency.

-- chris
 
M

Michael Borgwardt

VisionSet said:
Okay, I agree my designs above are brief.

2/ ... A wrapper takes an instance of the remote interface version and wraps
it to provide an implementation of the local interface. Thus providing one
type in two flavours.

Still what's the point? If all you gain by using this relatively complicated
setup is that you can catch the RemoteException in the Wrapper, I'd say that
having to deal with the RemoteException even in client code that uses only the
local version is less hassle.
 
V

VisionSet

Michael Borgwardt said:
Still what's the point? If all you gain by using this relatively complicated
setup is that you can catch the RemoteException in the Wrapper, I'd say that
having to deal with the RemoteException even in client code that uses only the
local version is less hassle.

Okay, I do see your point.

How about one interface that declares RemoteExceptions and a
HighLevelException that could wrap the RE.

Then in the client you take instances of this interface and wrap them so as
to remove the RE and wrap it in a HLException.

Then the client does not care how it got the object but has to deal with the
possiblity that the process of getting that object may well throw an
Exception hence dealing with the HLException.

IOExceptions are not suitably generic, eg SQLException does not extend IOE.
So some sort of custom wrapper exception (HLE) would fit the bill.

Struts Framework have methods that just throw Exception, but I think this is
bad practise.
 
V

VisionSet

Chris Uppal said:
VisionSet said:
Consider an object that needs to be accessible over a network, and also
locally. Which do you think is the best design:

1/ Have one interface that declares RemoteExceptions and [...]
2/ Have two interfaces almost identical [...]

If you are intending/expecting that you might be using the objects in both
local and remote configuration more-of-less interchangeably, then clearly you
have to go for (1).
...

Yes this is the situation, see another reply for elaboration.

Thanks Chris.
 
C

Chris Uppal

VisionSet said:
How about one interface that declares RemoteExceptions and a
HighLevelException that could wrap the RE.

How about the local interface declares exceptions that are based on what it was
trying to do (not what failed)

void frob() throws FailedToFrobException

and the remote implementation throws exceptions that further indicate that the
failure was caused by network issues, either:
by throwing a networking subclass of FailedToFrobException,
FailedToFrobCosTheNetworksBuggeredException,
or:
by throwing a vanilla FailedToFrobException with a "cause" which
indicates the network failure.

No need for wrappers then.

-- chris
 
J

Jesper Nordenberg

VisionSet said:
Consider an object that needs to be accessible over a network, and also
locally. Which do you think is the best design:

1/ Have one interface that declares RemoteExceptions and any other
Exceptions peculiar to the Object. Disadv: The object will never throw a
RemoteException if available locally.

2/ Have two interfaces almost identical except one throws the
RemoteExceptions in addition. Disadv: two interfaces to maintain that must
mirror each other.

I think you're looking at the problem from the wrong POV. You are
designing the interface on the basis of the implementations. You
should design the interface disregarding the implementations. Is it
reasonable to expect the users of the interface to handle the
RemoteExceptions? If not, they should not be part of the interface.

/Jesper Nordenberg
 
V

VisionSet

Chris Uppal said:
How about the local interface declares exceptions that are based on what it was
trying to do (not what failed)

void frob() throws FailedToFrobException

and the remote implementation throws exceptions that further indicate that the
failure was caused by network issues, either:
by throwing a networking subclass of FailedToFrobException,
FailedToFrobCosTheNetworksBuggeredException,
or:
by throwing a vanilla FailedToFrobException with a "cause" which
indicates the network failure.

No need for wrappers then.

You realise that a Remote object MUST declare RemoteExceptions.
So the client intercepting these objects must wrap them to abstract them
out.

How about this:


Client Remote
«intf» «intf»
| |
+-----+-------+ | UnicastRO
| | +--+---+ |
| | | | |
ClientImpl RemoteStubWrapper | RemoteImpl
RemoteStub ref----->RemoteStub Client ref


RemoteStubWrapper strips the RemoteExceptions off RemoteStub and its
methods wrap them in a DataTransferException that is declared by Client.
Remote is just the tagging interface.
RemoteImpl does not implement any of my interfaces, since it only wraps
a Client object and adds no logic of its own then the advantage of an
interface is gone. If another implementation of RemoteImpl is req'd then
all that needs to be done is pass it a different Client object.

Is my reasoning okay?

[Anyone know of an ASCII art UML editor?
not one that just approximates a freehand movement.
Is there perhaps a UML ASCII version specification ;-) ]
 
V

VisionSet

VisionSet said:
that

You realise that a Remote object MUST declare RemoteExceptions.
So the client intercepting these objects must wrap them to abstract them
out.

How about this:


Client Remote
«intf» «intf»
| |
+-----+-------+ | UnicastRO
| | +--+---+ |
| | | | |
ClientImpl RemoteStubWrapper | RemoteImpl
RemoteStub ref----->RemoteStub Client ref


RemoteStubWrapper strips the RemoteExceptions off RemoteStub and its
methods wrap them in a DataTransferException that is declared by Client.
Remote is just the tagging interface.
RemoteImpl does not implement any of my interfaces, since it only wraps
a Client object and adds no logic of its own then the advantage of an
interface is gone. If another implementation of RemoteImpl is req'd then
all that needs to be done is pass it a different Client object.

Is my reasoning okay?

Except for one almighty drawback at least - A requirement of RMI that you
must extend Remote and reference the stub through that. DOH!

So we are back to the two interfaces or one that includes RemoteExceptions.

Design is all very well, but RMI imposes some limitations.
 
C

Chris Uppal

VisionSet said:
Except for one almighty drawback at least - A requirement of RMI that you
must extend Remote and reference the stub through that. DOH!

Ah. I had missed (I suspect you hadn't mentioned) that you were using RMI.
That does change the rules of the game, and -- since I haven't used RMI -- I
don't feel competent to advocate "best practices".

Still, you should be able to get a clean design if you hide RMI, but that will
require wrappers after all. If I were faced with this, then I'd be temped to
automate it. Computers are well adapted to toil, so let it do the work. Why
keep a dog and lick your own ears ?

-- chris
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,777
Messages
2,569,604
Members
45,225
Latest member
Top Crypto Podcasts

Latest Threads

Top