2014-12-04 86 views
1

我有一个PluginClassLoader这是一个抽象类,它为我的项目的类加载器提供了99%的功能。我有两个子类(ServiceClassLoaderChannelClassLoader),它们延伸PluginClassLoader,仅比包装和一些自定义日志记录多一点。这两种实现中99%的逻辑是相同的。将扩展实现中的抽象类细节分开

我然后有一个PluginManager这也是其具有2个实施方式中,扩展它(ServiceManagerChannelManager),其是包装加上定制记录和更方便的构造的抽象类。

我遇到的麻烦是,在我的PluginManager中,必须能够实例化一个新的类加载器类型,即ServiceClassLoaderChannelClassLoader。我试图避免让我的PluginManager耦合到它当前的实现(即我希望能够添加未来实现的灵活性,但不会改变PluginManager的逻辑),所以尽量避免传入一些Enum并使用一些:

if (classLoaderType instanceof ClassLoaderType.SERVICE) { 
    // do logic for instantiating ServiceClassLoader 
} 

样品的类层次:

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 
} 

试图避免做这样的事情:

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 
    } 
} 
+1

我不清楚什么是确定要使用的类加载器。应该一个ServiceManager总是创建一个ServiceClassLoader,而其他一些PluginManager子类总是使用一个PluginClassLoader? – 2014-12-04 17:18:46

+0

@JonSkeet就是这样。我试图避免重写每个管理器的'loadPlugin()'方法,因为99%的细节是相同的,实际上只有这条线会有所不同。 – SnakeDoc 2014-12-04 17:19:50

回答

1

添加一个抽象方法PluginManager使一个类加载器和通话它根据需要。子类应覆盖该方法,返回相应的子类:

public abstract class PluginManager { 
    public PluginManager() { 
     pluginLoader = MakeClassLoader(); 
    } 
    ... 
    protected abstract PluginClassLoader MakeClassLoader(); 
} 
public class ServiceManager extends PluginManager { 
    ... 
    protected abstract PluginClassLoader MakeClassLoader() { 
     return new ServiceClassLoader(); 
    } 
} 
public class ChannelManager extends PluginManager { 
    ... 
    protected abstract PluginClassLoader MakeClassLoader() { 
     return new ChannelClassLoader(); 
    } 
} 

这实现了Factory Method设计模式。

2

您错过了enum的惊人灵活性,它们完全是自己发现的对象,因此可以实现接口。如果你让枚举本身能够工作,就像工厂一样简单。

下面是使用enum作为工厂的大大简化的演示。

interface Loader { 

    public Plugin load(); 
} 

enum PluginType implements Loader { 

    Service { 

       @Override 
       public Plugin load() { 
        return new ServiceClassLoader(); 
       } 
      }, 
    Channel { 

       @Override 
       public Plugin load() { 
        return new ChannelClassLoader(); 
       } 
      }; 
} 

public void loadPlugin(PluginType type) { 
    Plugin plugin = type.load(); 
} 

public void test() { 
    loadPlugin(PluginType.Channel); 
} 
2

三个选项:

  • 声明一个抽象newClassLoader()方法PluginManager,这是在ServiceManager覆盖,以返回一个新ServiceClassLoader
  • 您的参数类型更改从PluginTypeClass<? extends ClassLoader>,将其存储在一个字段(如classLoaderClass),然后只需拨打classLoader.newInstance()当您需要
  • Ma ke PluginType一个枚举(如果它不是已经有),它有自己的方法来创建一个新的ClassLoader

(目前尚不清楚是否需要PluginType其他原因 - 如果你不这样做,那么就没有它。)