I have a PluginClassLoader which is an abstract class that provides 99% of the functionality for my project's class loaders. I have 2 subclasses (ServiceClassLoader, and ChannelClassLoader) which extend PluginClassLoader and are little more than wrappers plus some customized logging. 99% of the logic is the same between the two implementations.
I then have a PluginManager which is also an abstract class which has 2 implementations that extend it (ServiceManager and ChannelManager) which are wrappers plus customized logging and a more convenient constructor.
The trouble I'm having is, in my PluginManager is must be able to instantiate a new class loader type, of either ServiceClassLoader or ChannelClassLoader. I'm trying to avoid having my PluginManager coupled to it's current implementations (ie. I want the flexibility of being able to add future implementations but not change PluginManager's logic), so trying to avoid passing in some Enum and using some:
if (classLoaderType instanceof ClassLoaderType.SERVICE) {
// do logic for instantiating ServiceClassLoader
}
Sample class hierarchy:
public abstract class PluginManager {
// logic for managing plugins and when to load them
// ...
// somewhere deep in a loadPlugin(final File directory) method
pluginLoader = new PluginClassLoader(); // <-- not valid, can't instantiate
// an abstract class,
// and it's of the wrong type!
}
public abstract class PluginClassLoader extends URLClassLoader {
// class loader logic
}
public class ServiceManager extends PluginManager {
// wrapper for PluginManager with some customized logging
}
public class ServiceClassLoader extends PluginClassLoader {
// wrapper for PluginClassLoader with some customized logging
}
Trying to avoid doing something like:
public abstract class PluginManager {
private final PluginType pluginType;
public PluginManager(final PluginType pluginType) {
this.pluginType = pluginType;
}
// logic ...
// somewhere deep in the loadPlugin(final File directory) method
if (pluginType instanceof PluginType.SERVICE) {
pluginLoader = new ServiceClassLoader();
// more logic
} else if (plugintype instanceof PluginType.CHANNEL) {
pluginLoader = new ChannelClassLoader();
// more logic
}
}

Three options:
newClassLoader() method in PluginManager, which is overridden in ServiceManager to return a new ServiceClassLoader etcPluginType to Class<? extends ClassLoader>, store it in a field (e.g. classLoaderClass), and then just call classLoader.newInstance() when you need toPluginType an enum (if it's not already) which have its own method to create a new ClassLoader.(It's not clear whether you need PluginType for other reasons - if you don't, then don't have it.)
See more on this question at Stackoverflow