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

huangapple go评论78阅读模式
英文:

How to make Java class know what to extend?

问题

请提供要翻译的文本,我会尽力为您提供翻译。

英文:

Assume we have three classes, Parent, Child1 extends Parent implements ISomething and Child2 extends Parent implements ISomethingElse. Now, I want to make Child3, which will either extends Child1 or Child2 depending on what Child3 receives.

The Child3 constructor is something like this:

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

How can I make Child3 know which class to extend?
(Don't answer Parent. Assume extending Parent will break the code and Parent doesn't implement anything)

答案1

得分: 1

You mentioned ISomething and ISomethingElse, which indicates that you want different features, capabilities, possibly combined, for Child classes.

In that case inheritance is unsuitable.

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.empty() : Optional.of(intf.cast(obj));
    }
}

interface Flying {
    void fly(double altitude);
}

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

pelican.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) { ... }
        });
    }
}

This is more versatile and more dynamic. But one might want:

class Pelican extends Bird implements Swimming {

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

In your case, you seem to want an object either has ISomething or ISomethingElse, so this would be a solution.

If all this seems too much overhead, consider delegation:

class Pelican extends Bird implements Swimming {
    private final Swimming swimmer = new SwimmingImplementation(this);

    @Override
    public void swim(boolean atSurface) {
        return swimmer.swim(atSurface);
    }
}

Pelican actually delegates to a Swimming implementation.

英文:

You mentioned ISomething and ISomethingElse. Which indicates that you want different features, capabilities, possibly combined, for Child classes.

In that case inheritance is unsuitable.

class Parent {

    // Untyped but safe.
    private Map&lt;Class&lt;?&gt;, Object&gt; capabilities = new HashMap&lt;&gt;();

    protected &lt;I&gt; void register(Class&lt;I&gt; intf, I obj) {
        capabilities.put(intf, obj);
    }

    public &lt;T&gt; Optional&lt;T&gt; lookup(Class&lt;T&gt; 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 -&gt; swimming.swim(true);
);

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

class Pelican extends Bird {

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

This is more versatile and more dynamic. But one might want:

class Pelican extends Bird implements Swimming {

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

In your case, you seem to want an object either has ISomething or ISomethingElse, so this would be a solution.

If all this seems too much overhead, consider delegation:

class Pelican extends Bird implements Swimming {
    private final Swimming swimmer = new SwimmingImplemetation(this);

    @Override
    public void swim(boolean atSurface) {
        return swimmer.swim(atSurface);
    }
}

Pelican actually delegates to a Swimming implementation.

答案2

得分: 0

你不能。继承结构在编译时定义(除非你使用魔法)。

你需要创建两个类,并将你的构造函数替换为工厂方法(或一对工厂方法)。

附注:如果可能的话,你可以考虑用委托代替继承。

英文:

You can't. Inheritance structure are defined at compile time (unless you use magic).

You have to create two classes and replace your constructor with factory method (or pair of factory methods).

PS: You may consider replacing inheritance with delegation if it possible.

答案3

得分: 0

你可以优先使用组合而不是继承:

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 the type of the contained value.
// If you don't want to check types, you can
// create adapter classes for each subclass of the 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();
        }
    }
}
英文:

You can prefer composition over inheritance:

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&lt;T extends Parent&gt; {
	
	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();
		}
	}
}

huangapple
  • 本文由 发表于 2020年8月14日 14:25:24
  • 转载请务必保留本文链接:https://go.coder-hub.com/63407619.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定