简体   繁体   English

将抽象类详细信息与扩展实现分离

[英]Decouple abstract class details from extended implementations

I have a PluginClassLoader which is an abstract class that provides 99% of the functionality for my project's class loaders. 我有一个PluginClassLoader ,它是一个抽象类,可为项目的类加载器提供99%的功能。 I have 2 subclasses ( ServiceClassLoader , and ChannelClassLoader ) which extend PluginClassLoader and are little more than wrappers plus some customized logging. 我有2个子类( ServiceClassLoaderChannelClassLoader ),它们扩展了PluginClassLoader ,并且只不过是包装器和一些自定义的日志记录。 99% of the logic is the same between the two implementations. 两种实现之间99%的逻辑是相同的。

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. 然后,我有一个PluginManager ,它也是一个抽象类,具有2个扩展它的实现( ServiceManagerChannelManager ),这些实现是包装程序以及自定义日志记录和更方便的构造函数。

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 . 我遇到的麻烦是,在我的PluginManager中,必须能够实例化ServiceClassLoaderChannelClassLoader的新类加载器类型。 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: 我试图避免将我的PluginManager与当前的实现耦合在一起(即,我希望能够增加将来的实现,但又不更改PluginManager的逻辑的灵活性),因此尝试避免传入一些Enum并使用一些:

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

You are missing out on the amazing flexibility of enum s, they are fully blown objects in their own right and can therefore implement interfaces. 您会错过enum的惊人灵活性,它们本身就是完全被吹灭的对象,因此可以实现接口。 If you make the enum itself capable of functioning as the factory all becomes simple. 如果使枚举本身能够充当工厂,那么一切将变得简单。

Here's a greatly simplified demonstration of using an enum as a factory. 这是将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);
}

Three options: 三种选择:

  • Declare an abstract newClassLoader() method in PluginManager , which is overridden in ServiceManager to return a new ServiceClassLoader etc PluginManager声明一个抽象的newClassLoader()方法,在ServiceManager中将其重写以返回新的ServiceClassLoader
  • Change your parameter type from PluginType to Class<? extends ClassLoader> 将参数类型从PluginType更改为Class<? extends ClassLoader> Class<? extends ClassLoader> , store it in a field (eg classLoaderClass ), and then just call classLoader.newInstance() when you need to Class<? extends ClassLoader> ,将其存储在字段中(例如classLoaderClass ),然后在需要时仅调用classLoader.newInstance()
  • Make PluginType an enum (if it's not already) which have its own method to create a new ClassLoader . PluginType一个枚举(如果尚未枚举),该枚举具有自己的方法来创建新的ClassLoader

(It's not clear whether you need PluginType for other reasons - if you don't, then don't have it.) (不清楚是否由于其他原因是否需要PluginType如果不需要,则不要。)

Add an abstract method to PluginManager to make a class loader, and call it as needed. 将抽象方法添加到PluginManager以创建类加载器,然后根据需要调用它。 Subclasses should override that method, returning the appropriate subclass: 子类应重写该方法,并返回适当的子类:

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();
    }
}

This implements the Factory Method design pattern. 这实现了工厂方法设计模式。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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