A weird little problem about handling objects without knowing whatthey are

T

Tom Anderson

Hello!

I wonder if anyone has any ideas on how or whether i can do something.

I have an interface a bit like this:

public interface Machine {
}

public interface MachineManager {
public Machine getByID(String id) ;
public List<Machine> getAllInRoom(int roomNumber) ;
public void switchOn(Machine m) ;
public void switchOff(Machine m) ;
}

With a couple of different implementations.

Now, i know what you're thinking: why aren't switchOn and switchOff
methods on Machine?

The reason is because i've told a bit of a lie. I do have a couple of
classes that are like MachineManager, but in each case, Machine is a
totally different thing. It's more like:

public interface FruitManager {
public Fruit getByID(String id) ;
public void switchOn(Fruit f) ;
}

public interface CloudManager {
public Cloud getByID(String id) ;
public void switchOn(Cloud d) ;
}

Fruit and Cloud do not share any common base type below Object, and thus
there's no type that has a switchOn() that i could use for both. They're
both third-party library classes, so i can't do anything about this.

But still, i want to be able to write client code that gets things by ID
or room number, and then switches them on and off - without knowing what
they are.

I also want to ensure that the managers are only ever fed instances of the
right kind of object. If someone feeds a Fruit to a CloudManager, there'll
be hell to pay.

I think there's no way to do this using polymorphism. Is there any way to
do it using generics? I haven't been able to come up with anything, but i
feel like i should be able to say something like:

ThingManager<T> mgr = ... ;
T thing = mgr.getById("cirrusberry") ;
mgr.switchOn(thing) ;

But without having to make the calling code generic, and supply a type
parameter to that. To sort of have a floating type variable. Does that
make any sense? Can i use a wildcard here somewhere?

If there's no typological solution, i can see two options.

Option zero is just to use Object for the things, have no static type
safety, and rely on dynamic safety. It'll work, but it's not exactly
pretty.

A slightly better option is to wrap the things inside a polymorphic
wrapper:

public interface Manageable {
}

public class FruitWrapper implements Manageable {
// ...
}

public class CloudWrapper implements Manageable {
// ...
}

public interface Manager {
public Manageable getByID(String id) ;
public void switchOn(Manageable m) ;
}

This gives me a measure of type safety, but doesn't actually stop someone
passing a CloudWrapper to a FruitManager. Although in this case, i could
dispense with the switchOn method in Manager, and implement it as an
instance method in Manageable, so maybe this problem would evaporate.

The second is to hide the objects altogether, and have an interface that
looks like:

public interface Manager {
public void switchOnByID(String id) ;
public void switchOnAllInRoom(int roomNumber) ;
}

Or possibly, avoiding massive duplication:

public class Selector {
public Selector(String ID) ;
public Selector(int roomNumber) ;
}

public interface Manager {
public void switchOn(Selector s) ;
}

Which would work, but doesn't excite me very much.

Any ideas?

tom

PS Fruit and Cloud are actually Elements, from the W3C DOM and DOM4J
packages respectively.

PPS DOM4J has dual-interfaced objects, which are both DOM4J Elements and
W3C Elements. That might be a solution, but i'd like to avoid that if
possible, since the object creation is happening in another third-party
library, and i'd have to fiddle with that!
 
M

Mark Space

Tom said:
> A slightly better option is to wrap the things inside a polymorphic
wrapper:

I did like this best. If I understand what you are trying to do, you're
having problems like this:


class Wrapper {}
class Cloud extends Wrapper {}
class Fruit extends Wrapper {}

interface Manager{
void switchOn( Wrapper w );
}

class CloudManager implements Manager {
@Override
public void switchOn( Cloud c ) {}
}

which almost works, but fails because the switchOn method in
CloudManager doesn't actually over ride the switchOn method in the
interface Manager. Not to worry, there is a solution:


class Wrapper {}
class Cloud extends Wrapper {}
class Fruit extends Wrapper {}

interface Manager<WRAPPER extends Wrapper> {
void switchOn( WRAPPER w );
}

class CloudManager implements Manager<Cloud> {
@Override
public void switchOn( Cloud c ) {}
}


I can't promise that this construct won't bite you in some other way,
but it does compile, and I think it gets you what you want.

I wish I could take credit for this idea, but I can't. Our local guru
Stefan Ram is the author of this idea.

<http://groups.google.com/group/comp.lang.java.programmer/browse_thread/thread/c651aaf98394214b?fwc=2>
 
A

Abhijat Vatsyayan

Tom said:
Hello!

I wonder if anyone has any ideas on how or whether i can do something.

I have an interface a bit like this:

public interface Machine {
}

public interface MachineManager {
public Machine getByID(String id) ;
public List<Machine> getAllInRoom(int roomNumber) ;
public void switchOn(Machine m) ;
public void switchOff(Machine m) ;
}

With a couple of different implementations.

Now, i know what you're thinking: why aren't switchOn and switchOff
methods on Machine?

The reason is because i've told a bit of a lie. I do have a couple of
classes that are like MachineManager, but in each case, Machine is a
totally different thing. It's more like:

public interface FruitManager {
public Fruit getByID(String id) ;
public void switchOn(Fruit f) ;
}

public interface CloudManager {
public Cloud getByID(String id) ;
public void switchOn(Cloud d) ;
}

Fruit and Cloud do not share any common base type below Object, and thus
there's no type that has a switchOn() that i could use for both. They're
both third-party library classes, so i can't do anything about this.

But still, i want to be able to write client code that gets things by ID
or room number, and then switches them on and off - without knowing what
they are.

I also want to ensure that the managers are only ever fed instances of
the right kind of object. If someone feeds a Fruit to a CloudManager,
there'll be hell to pay.

I think there's no way to do this using polymorphism. Is there any way
to do it using generics? I haven't been able to come up with anything,
but i feel like i should be able to say something like:

ThingManager<T> mgr = ... ;
T thing = mgr.getById("cirrusberry") ;
mgr.switchOn(thing) ;

But without having to make the calling code generic, and supply a type
parameter to that. To sort of have a floating type variable. Does that
make any sense? Can i use a wildcard here somewhere?

If there's no typological solution, i can see two options.

Option zero is just to use Object for the things, have no static type
safety, and rely on dynamic safety. It'll work, but it's not exactly
pretty.

A slightly better option is to wrap the things inside a polymorphic
wrapper:

public interface Manageable {
}

public class FruitWrapper implements Manageable {
// ...
}

public class CloudWrapper implements Manageable {
// ...
}

public interface Manager {
public Manageable getByID(String id) ;
public void switchOn(Manageable m) ;
}

This gives me a measure of type safety, but doesn't actually stop
someone passing a CloudWrapper to a FruitManager. Although in this case,
i could dispense with the switchOn method in Manager, and implement it
as an instance method in Manageable, so maybe this problem would evaporate.

The second is to hide the objects altogether, and have an interface that
looks like:

public interface Manager {
public void switchOnByID(String id) ;
public void switchOnAllInRoom(int roomNumber) ;
}

Or possibly, avoiding massive duplication:

public class Selector {
public Selector(String ID) ;
public Selector(int roomNumber) ;
}

public interface Manager {
public void switchOn(Selector s) ;
}

Which would work, but doesn't excite me very much.

Any ideas?

tom

PS Fruit and Cloud are actually Elements, from the W3C DOM and DOM4J
packages respectively.

PPS DOM4J has dual-interfaced objects, which are both DOM4J Elements and
W3C Elements. That might be a solution, but i'd like to avoid that if
possible, since the object creation is happening in another third-party
library, and i'd have to fiddle with that!

From what I understand - you have objects that have same interface (not
java interface, but interface in the sense of operations supported by an
object) but different runtime types and static/compile time type
checking is messing things up. I suppose changing the type of object at
runtime is just about as good (or bad) as using reflection.

The wrapper is a good way to go about this.

Alternatively (and only slightly differently), you could use
java.lang.reflect.Proxy . You could write a common getByID
implementation for the Manager -

Manageable
{
void switchSelfOf() ;
void swithSelfOff() ;
}
Manager
{
Manageable getByID(String id) ;
// .. other methods ..
}

abstract class AbstractManager implements Manager
{
public Manageable getByID(String id)
{
Object iHaveNoCompileTimeType = getUntypedObjectByID(id) ;
// now convert this to a Manageable using proxy
// which, in the end, uses reflection ..
}
protected abstract Object getUntypedObjectByID(String id) ;
}

For your case, however, I would suggest using a java.lang.reflect.Proxy
to do a type conversion since the interfaces (the ones you are using)
are, I suppose, identical.

So a method like

w3c.Element convertFromDOM4JToW3C(dom4j.Element element)
{
// wrap up element into a proxy .. which will effectively
// change the runtime type of "element" object from
// dom4j.Element to w3c.Element
}


should be sufficient to convert between the two types.


Abhijat
 
D

Daniel Pitts

Tom said:
Hello!

I wonder if anyone has any ideas on how or whether i can do something. [...snip...]

A slightly better option is to wrap the things inside a polymorphic
wrapper:

public interface Manageable {
}

public class FruitWrapper implements Manageable {
// ...
}

public class CloudWrapper implements Manageable {
// ...
}

This seems like the best idea. If you want to find the Pattern, I
believe its called the Adapter Pattern. It actually buys you at *least*
three things in this case.

1. Type safety. If you require a FruitWrapper, you can ask for it directly.

public void actOnFruit(FruitWrapper wrapper) {}

2. Polymorphism. (For your use case especially)

3. Encapsulation. Today FruitWrapper wraps an Element. Tomorrow it
could wrap something else altogether, or not even be a Wrapper at all.

There are other benefits to using this pattern, but I would say those
are the biggest ones.

Hope this helps,
Daniel.
 

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,744
Messages
2,569,483
Members
44,902
Latest member
Elena68X5

Latest Threads

Top