简体   繁体   中英

How can Java return an object with class dependent on a specified parameter?

I am writing test code for a web page that supports different types of widgets, each of which I have represented with a class ( XWidget extends AbstractWidget , YWidget extends AbstractWidget etc.), and I need a simple way of creating Widget objects. Ideally, it would look something like this:

public static AbstractWidget getWidget(ObjectType widgetType) {
  //return some subclass of AbstractWidget
}
public enum ObjectType {
  X(XWidget.class), Y(YWidget.class);
  //include constructor etc.
}

I currently have a rather messy-looking implementation that involves passing in Class objects as parameters (see example below) but this can't be the best way of doing it.

public static <T extends AbstractWidget<?>> T getWidget(Class<T> objectType) {
  try {
    return objectType.getConstructor(new Class[] {WebElement.class}).newInstance(/*some WebElement*/);
  } catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException | NoSuchMethodException | SecurityException e) {
    e.printStackTrace();
  }
  return null;
}
public <T extends AbstractWidget<?>> T createWidget(Class<T> objectType) {
  //create widget of type objectType
  return getWidget(objectType);
}

Any help in getting the Generics stuff (which I don't really understand) working would be greatly appreciated, or even just a completely different approach.

You could make the enum responsible for instantiating the widgets:

public static AbstractWidget getWidget(ObjectType widgetType) {
    return widgetType.instantiate();
}

public enum ObjectType {
    X {
        @Override
        XWidget instantiate() {
            return new XWidget();
        }
    },
    Y {
        @Override
        YWidget instantiate() {
            return new YWidget();
        }
    };
    abstract AbstractWidget instantiate();
}

If you want to optimize for better testability, you might want to use creation methods (or directly use injection, if your scenario allows that).

public class WidgetClientClass {
    protected AbstractWidget myWidget;
    protected AbstractWidget getWidget() {
        return myWidget;
    }
    protected void createXWidget() {
        myWidget = new XWidget();
    }
    protected void createYWidget() {
        myWidget = new YWidget();
    }
}

public class WidgetClientTest {
    private class WidgetClientClassForTest extends WidgetClientClass {

        public void setWidget(AbstractWidget whateverFitsTheTest) {
            myWidget = whateverFitsTheTest;
        }
    }

    public void testZWidget {
        WidgetClientClassForTest instance = new WidgetClientClassForTest();
        instance.setWidget(new ZWidget());
        // do your tests
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM