views:

133

answers:

2

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 As 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.

+1  A: 

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);
}
Steve B.
Ah, no - I'm not looking for a succession of types, but rather a succession of instances. I've tried to clarify my question in the EDIT.
Carl
A: 

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.

Andrzej Doyle
Sort of - what I'm looking to define is that class can build itself sequentially, which as far as I've found, means the interface has to specify a generic parameter (the class to be build). However, I also have the case the classes that should be doing this are in an inheritance hierarchy (and not in the decorator style - functionality is added, not just modified), which precludes implementing an interface multiple times with different parameters.Anyway, I'm looking at solving the problem with AspectJ/AOP style programming.
Carl