Reputation: 7544
I have an interface to describe when a class can create a "next" version of itself:
public interface Prototypeable<Type extends Prototypeable<Type>> {
public Type basePrototype(); // the zeroth raw instance of Type
public Type nextPrototype(); // the next instance of Type
}
to be used with
public class Prototyper {
public static <Type extends Prototypeable<Type>> List<Type> prototypeFactor(int numberOfInstances, Type proto) {
List<Type> result = new ArrayList<Type>(numberOfInstances);
Type holder = proto.basePrototype();
result.add(holder);
for (int i=1; i<numberOfInstances;i++) result.add(holder = holder.nextPrototype());
return result;
}
Now, I have a base class A implements Prototypeable<A>
, and an subclass AButMore extends A
. I would like to have AButMore extends A implements Prototypeable<AButMore>
, but this isn't allowed (cannot implement generic interfaces multiple times with different classes). Also note that A
and AButMore
both implement some other interfaces, and that implementation is identical from A
to AButMore
.
Suggestions for getting around this? I can't seem to fiddle around the generic problem, so I've considered a few alternate designs:
pseudo-decorating both classes - i.e., having a base class that doesn't implement the Prototypeable
interface, inheriting from that to the proper subclass and then having both classes extended to Prototypeable versions of themselves. The downside seems to be a profusion of classes.
not extending A
to AButMore
and instead constructing AButMore
from A
s and delegating all the replicated methods. However, delegate code always seems silly to me, especially when every method that could be inherited is going to be delegated with no modifications.
having Prototypeable
specify Object
as the return type, and having the factory take a Class
parameter for casting. The downside here is that this can allow for unsafe casts if used improperly.
EDIT: To clarify: the intent is to manufacture instances that have some sort of sequential dependency, without having a class variable. The simplest example would be if they each have an index variable - basePrototype would provide a 0-index instance, and nextPrototype() would provide an index+1 instance (based on the index of the instance that the method was called from). That particular case is a little simplistic (and probably could be implemented in a simpler fashion), but covers the idea.
EDIT: For further clarification, here is the exact current implementation (I am using the third alternative above):
public class BuildFromPrototype {
public static <T extends Prototypeable> List<T> build(int buildCount, Class<T> protoClass, T prototype) {
if (protoClass==null || prototype==null || buildCount<=0) return null;
if( protoClass.isInstance(prototype.basePrototype()) && protoClass.isInstance(prototype.nextPrototype()) ) {
List<T> result = new ArrayList<T>(buildCount);
T pHolder = protoClass.cast(prototype.basePrototype());
result.add(pHolder);
for (int i=1;i<buildCount;i++)
result.add(pHolder = protoClass.cast(pHolder.nextPrototype()));
return result;
} else return null;
}
public interface Prototypeable {
public Object nextPrototype();
public Object basePrototype();
}
}
I think this handles misuse (returning null
is one option, an Exception
would have also been reasonable), but testing for valid casts could be expensive. This form of casting might also be expensive - I don't know much about the Class
class.
Upvotes: 1
Views: 518
Reputation: 103787
The only relation that can be expressed in Java's generics is the super-/subtype relationship. To me, it doesn't sound like you want more and more specific classes (i.e. subtypes), but rather "sibling" implementations of the same interface. You cannot express this using purely generic types alone - you can't annotate classes so that Java knows that MyImplB is the "next" implementation for MyImplA.
The easiest way that you can communicate this information is to use the class literal, as you're doing in your last case. Using this you can strictly restrict the type of the next implementation. However, depending on what you want to do, the runtime checking via isInstance
is perhaps not the most useful restriction; compile-time checking would generally be a better option.
In which case, you'd need two generic parameters in play - one for the type of the prototype, and one for the class of the next version. Based on your first snippet, it sounds more like each Type should also be parameterised with the type of the next version:
/**
* @param N the specific class of the next type
*/
public class/interface Type<N extends Type>
{
public Type<?> basePrototype();
public N nextPrototype();
}
public class MyImplA implements Type<MyImplB> { ... }
public class MyImplB implements Type<MyImplC> { ... }
// ... and so on
This will then enforce statically the link between the different type implementations.
I'm not sure how much good it would do you in the situation you've shown, though, as there's not really much support for type-safe heterogenous containers. Since you're putting everything in an ArrayList, you wouldn't be able to assert that the contents of the list were more specific than Type<?>
. It would help with handling individual operations, though.
Upvotes: 0
Reputation: 57284
I'm not sure what you want to do with defining the "next" versions, it looks like you want to do metaclass programming, which you can't do in java, i.e I can't see how you can have the generic type system manage a succession of types determined at runtime, since they're type-erased and don't exist at runtime. How about an interface that defines a mapping from one type to the next, e.g. something like
public interface PrototypeMapping<U extends Prototypeable<Type>,V extends U>{
public V mapTo(U u);
}
Upvotes: 1