I am trying to write a set of User Interfaces that operate similarly for multiple classes, which all extend an abstract class Category: HouseCategory extends Cat开发者_开发问答egory, CarCategory extends Category
Most of the code works fine just by using polymorphism, but there is one section where I need to create a new instance of the extended category
Obj foo = new HouseCategory(a, b, c)
How can I make this work for all subclasses of Category? - they all have the same constructor arguments. I don't know much about generics, but is it possible for me to have the UI class defined as
public class UserInterface <T extends Category> extends JFrame {
or possibly
public class UserInterface extends JFrame {
public UserInterface(Class<T extends Category> clazz) {
and build from there? Help much appreciated.
EDIT: Also, is it possible to get a static field from the generic class? I'd rather not have to have a statement checking "if (clazz instanceof HouseCategory) name = HouseCategory.NAME" as there may be hundreds of classes.
Introduce a new factory to create the category objects or the user interfaces. The factory needs to be extended whenever you add a new category, but that shouldn't be a big problem:
public class CategoryFactory {
public static enum Type {HOUSE, CAR}
public static Category createCategory(Type type, Param a, Param 2, Param b) {
if (type == null) return null;
switch(Type) {
case HOUSE: return new HouseCategory(a,b,c);
case CAR: return new CarCategory(a,b,c);
}
return null; // or throw exception -> tells, that a new enum is not handled yet
}
}
Then, if you protect
the constructors in the category subclasses and keep those subclasses and the factory in one package, you can make it pretty difficult to bypass the factory.
Generics can't really help you with this due to type erasure. At runtime your code doesn't "know" the values of the type parameters.
One approach would be to use the factory pattern. Create a factory class for each Category and have these all implement a common factory interface (probably CategoryFactory). Then give factory objects to the UserInterface rather than Class objects.
Another approach would be to use reflection to invoke the constructor on the Class object. I'm not a fan of this approach as it throws compile time checking out the window, but it would involve using the getConstructor method on the Class.
Pass the class to the interface. Use reflection to invoke the constructor and access the NAME field. But it's better to employ instance methods that subclass can override:
/** subclass must have the default constructor */
abstract class Category
abstract void init(a, b, c);
abstract String name();
class HouseCategory extends Category
void init(a, b, c){ ... }
String name(){ return "House"; }
class UserInterface
UserInterface(clazz)
Category foo = (Category)clazz.newInstance();
foo.init(a,b,c);
String name = foo.name();
精彩评论