如何使Java类知道要扩展什么?

问题描述

假设我们有三个类,ParentChild1 extends Parent implements ISomethingChild2 extends Parent implements ISomethingElse。现在,我要制作Child3,根据extends收到的内容,它可以Child1 Child2Child3

Child3构造函数是这样的:

public <T extends Parent> Child3(T child) {}

如何使Child3知道要扩展哪个类? (不要回答Parent。假设扩展Parent会破坏代码,而Parent则不会实现任何内容

解决方法

您提到了ISomething和ISomethingElse。这表示您希望子类具有不同的功能(可能组合在一起)。

在这种情况下,继承是不合适的。

SDL_WaitEvent

这是更加通用和动态的。但有人可能想要:

class Parent {

    // Untyped but safe.
    private Map<Class<?>,Object> capabilities = new HashMap<>();

    protected <I> void register(Class<I> intf,I obj) {
        capabilities.put(intf,obj);
    }

    public <T> Optional<T> lookup(Class<T> intf) {
        Object obj = capabilities.get(intf);
        return obj == null ? Optional.emtpy() : Optional.of(intf.cast(obj));
    }
}

interface Flying {
    void fly(double altitude);
}

Parent pelican = new Pelican();
Flying flying = pelical.lookup(Flying.class).orElse(null);
flying.fly(0.5);

pelical.lookup(Swimming.class).ifPresent(
    swimming -> swimming.swim(true);
);

class Bird extends Parent { ... } // With Swimming capability

class Pelican extends Bird {

    public Pelican() {
        register(Swimming.class -> new Swimming() {
            @Override public void swim(boolean atSurface) { ... }
        });
    }
}

在您的情况下,您似乎想要一个对象具有ISomething或ISomethingElse,因此这是一个解决方案。

如果这一切似乎开销太大,请考虑授权

class Pelican extends Bird implements Swimming {

    @Override
    public void swim(boolean atSurface) {
        return lookup(Swimming.class).get().swim(atSurface);
    }
}

鹈鹕实际上是委托给游泳实施的。

,

不能。继承结构是在编译时定义的(除非您使用魔术)。

您必须创建两个类,然后将构造函数替换为工厂方法(或一对工厂方法)。

PS:如果可能,您可以考虑用委派替换继承。

,

与继承相比,您更喜欢合成:

public class Parent {}

public interface ISomething {}

public interface ISomethingElse {}

public class Child1 extends Parent implements ISomething {}

public class Child2 extends Parent implements ISomethingElse {}

// Child 3 does not inherits from other classes
public class Child3<T extends Parent> {
    
    private final T child;
    
    public Child3(T child) {
        this.child = child;
    }
    
    public T getChild() {
        return this.child;
    }
}

// Consumer checks type of contained value.
// If you dont want to check types you can
// create adapter classes for each subclass of parent
public class Consumer {
    
    public void test(Child3 child3) {
        
        if (child3.getChild() instanceof Child1) {
            final Child1 child1 = (Child1) child3.getChild();
        }
        if (child3.getChild() instanceof Child2) {
            final Child2 child2 = (Child2) child3.getChild();
        }
    }
}