【问题标题】:How to make Java class know what to extend?如何让 Java 类知道要扩展什么?
【发布时间】:2020-12-04 00:54:25
【问题描述】:

假设我们有三个类,ParentChild1 extends Parent implements ISomethingChild2 extends Parent implements ISomethingElse。现在,我想创建Child3,这将是extends Child1Child2,具体取决于Child3 收到的内容。

Child3 构造函数是这样的:

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

如何让Child3 知道要扩展哪个类? (不要回答Parent。假设扩展Parent 会破坏代码并且Parent 没有实现任何东西)

【问题讨论】:

  • 听起来你想要一个“创作模式”。常见的例子有BuilderFactoryAbstractFactory等。
  • 这在 Java 中是不可能的。考虑定义类Child3Child4 分别扩展Child1Child2。如果您需要创建这些类的对象,请动态定义一个工厂方法,该方法要么返回一个实例,要么返回另一个实例。
  • 但是如果我需要从Parent 覆盖Child3 中的方法怎么办?有没有办法覆盖不同类的方法?

标签: java class extends


【解决方案1】:

你提到了 ISomething 和 ISomethingElse。这表明您希望子类具有不同的特性、功能,可能是组合的。

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

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

这更通用,更动态。但有人可能想要:

class Pelican extends Bird implements Swimming {

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

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

如果所有这些看起来开销太大,请考虑委派

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

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

Pelican 实际上委托给 Swimming 实现。

【讨论】:

    【解决方案2】:

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

    您必须创建两个类并用工厂方法(或一对工厂方法)替换您的构造函数。

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

    【讨论】:

      【解决方案3】:

      您可以更喜欢组合而不是继承:

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-11-24
        • 2013-08-02
        • 2017-09-30
        • 1970-01-01
        • 1970-01-01
        • 2016-08-16
        • 2015-07-03
        • 2021-12-14
        相关资源
        最近更新 更多