Java:如何为抽象类的子类创建一个包装类,它实例化包装的类

时间:2017-01-30 22:14:33

标签: java generics

我有一个接口(让我们称之为FooInterface),我在一个抽象类的子类(我们称之为A,B,C)的各个子类(我们可以称之为X,Y,Z)中实现(让我们称它为酒吧)。但是必须在所有这些方法中编写(复制)相同的方法是浪费的,更重要的是,考虑到它们只是从接口扩展的子类+那些方法。

因此,我决定删除X,Y,Z层,并使FooInterface成为包装Bar-instances的实际类Foo。但我似乎无法找到一个好方法,我的第一个想法是一个通用的包装类:

public abstract class Bar {/*code*/}

public class A extends Bar {/*code*/}
public class B extends Bar {/*code*/}
public class C extends Bar {/*code*/}

/*
 * Removed thanks to using the nifty wrapper Foo now!
 * I am so happy I decided to do this,
 *  can't imagine the horrors I would dream of at night if I had
 *  an extra redundant class for each subclass of Bar like this!
 * public class X extends A implements FooInterface {/*implementing FooInterface*/}
 * public class Y extends B implements FooInterface {/*implementing FooInterface*/}
 * public class Z extends C implements FooInterface {/*implementing FooInterface*/}
*/

public class Foo<T extends Bar> {
    private T t;
    public Foo() {t = /*code instantiating T*/}
    //code implementing the methods from FooInterface
}

然而,这不起作用,因为在java中使用泛型类型时,获取T的实例似乎很难。

我考虑过做类似于将T作为枚举的事情:

public class Foo<T extends BarType> {
    public enum BarType { A, B, C; }
    private T t;
    public Foo() {
        switch(T) {
            // code instantiating t by using an ugly hard-coded switch-case...
            // please don't make me!
        }

        //code implementing the methods from FooInterface
    }
}

但我无法想象如何能够使用这样的枚举。所以在这一点上,我正在认真考虑放弃空构造函数,并按照以下方式做一些事情:

// No longer generic and instead pass type to constructor!
public class Foo {
    public enum BarType { A, B, C; }
    private T t;
    public Foo(Bartype bartype) {
        switch(T) {
            // code instantiating t by using an ugly hard-coded switch-case...
            // please don't make me!
        }

        //code implementing the methods from FooInterface
    }
}

虽然为了避免必须进行硬编码的switch语句,我更倾向于这个版本:

public class Foo<T extends Bar> {
    private T t;
    // Foo is used as such: 'Foo<T> foo = new Foo<T>(T.class);'
    public Foo(Class<T> clazz) throws InstantiationException,
            IllegalAccessException {
        // why is it customary to spell this with z?
        t = clazz.newInstance()

        //code implementing the methods from FooInterface
    }
}

如何在java中正确制作这样的包装器?我也考虑过其他方法,例如在将工厂传递给构造函数或执行ParameterizedType事物的泛型类中,或者在非泛型中直接将正确类的实例直接传递给构造函数。但所有这些看起来像是一个很大的麻烦而且非常丑陋,我甚至更喜欢带有类似枚举的硬编码开关盒......

编辑: 正如有些人问我为什么不让Bar实现FooInterface,这是因为Bar是一个很好的纯数据结构,而FooInterface的作用是使它有一些对更专业的实现有用的方法。例如,Bar等是正常的列表(所以它可能我甚至不是实现它们的那个),但是我的实现还必须跟踪哪些是很酷的:

public abstract class List; // Bar
public class LinkedList extends List; // A
public class ArrayList extends List // B
public interface CoolLists { // FooInterface
    boolean isCool();
    void setCool(boolean cool);
}
public class CoolLinkedList extends LinkedList implements CoolList; // X
public class CoolArrayList extends ArrayList implements CoolList; // Y

不,我不是实际重新实现列表,如果我想跟踪'酷列表',我不会在其中存储布尔值而是使用像HashSet这样的东西存储'酷'的:P

1 个答案:

答案 0 :(得分:3)

您应该将Class<T>传递给Supplier<T>的构造函数,而不是传递Foo。要获取实例,只需致电t = supplier.get();即可。这可以防止您不得不处理反射问题。要获得供应商,您可以使用A::newB::newC::new。要创建Foo的实例,您可以调用:

new Foo<A>(A::new);

没有反映,也没有涉及异常处理。

另见this答案。