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!
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!