简体   繁体   English

选择在运行时从java扩展的子类

[英]Choose which subclass to extend from at runtime in java

I have two classes (say B & C) that both derive from a class (say A). 我有两个类(比如B&C),它们都来自一个类(比如说A)。 Now I need to write a class (say D) that should dynamically derive either from B or C at runtime. 现在我需要编写一个类(比如D),它应该在运行时从B或C动态派生。

B, C & A are classes provided to me through libraries and the only class in my control is D class. B,C&A是通过图书馆提供给我的课程,我控制的唯一课程是D课程。 How do I write D with respect to constraints mentioned above. 如何针对上述约束编写D. Obviously B and C have come from different vendors and hence would need different methods to be overridden in D depending on which is its parent class. 显然,B和C来自不同的供应商,因此需要在D中覆盖不同的方法,具体取决于它的父类。

I cannot write different versions of D that would subclass from B & C since the override methods would have same code under different method names. 我不能编写从B&C继承的不同版本的D,因为覆盖方法在不同的方法名下会有相同的代码。

You should define an interface I , then define concrete implementations that correspond to B and C . 您应该定义接口I ,然后定义与BC对应的具体实现。 At runtime you can determine which implementation of I is necessary, perhaps using a factory method. 在运行时,您可以使用工厂方法确定I哪个实现是必要的。 Then your code need only call methods of I instead of methods of B or C . 那么你的代码只需要调用I的方法而不是BC的方法。

EDIT 编辑

There seems to be some confusion about how this works. 关于它是如何工作的似乎有些混乱。 What you want is for your business logic to operate on a consistent, stable API that belongs to you. 您想要的是您的业务逻辑在属于您的一致,稳定的API上运行。 For this you create an interface which we'll call I . 为此你创建了一个我们称之为I的界面。 Now you need implementation classes for the different external classes you need to adapt to ( A , B , and C ). 现在,您需要适应( ABC )所需的不同外部类的实现类。 It might look something like this: 它可能看起来像这样:

public interface I {
    void doSomething();
}

public class IA implements I {
    private A a;

    public IA(A a) {
        this.a = a;
    }

    public void doSomething() {
        // specific to A
        a.doSomethingUnique();
    }
}

// similar implementation classes for B and C

Now you need to obtain an instance of I at runtime specific to your current situation. 现在,您需要在运行时获取特定于当前情况的I实例。 Whatever informs you about which specific class is in use at runtime can be used for this purpose. 无论通知您何时在运行时使用哪个特定类都可以用于此目的。 At worst, you can do this: 在最坏的情况下,你可以这样做:

// in some util class
public static I getI(Object obj) {
    if (obj instanceof A) {
        return new IA((A) obj);
    } else if (obj instanceof B) {
        return new IB((B) obj);
    } else if (obj instanceof C) {
        return new IC((C) obj);
    }
    // maybe throw an exception? or return a mock I implementation?
}

Now all your business logic refers only to instances of I and calls methods defined in your interface, abstracting away the different concrete classes you have no control over. 现在,您的所有业务逻辑仅引用I实例并调用接口中定义的方法,从而抽象出您无法控制的不同具体类。

You can do it with private inheritance. 您可以使用私有继承来完成它。

If you have : 如果你有 :

class A
{
  public void methodA() {...}
}
class B extends A
{
  public void methodB() {...}
}
class C extends A
{
  public void methodC() {...}
}

D would be implemented as : D将实现为:

class D
{
  private B b;
  private C c;
  private D() {}
  public static D instantiateAsB()
  {
    D res = new D();
    res.b = new B();
  }
  public static D instantiateAsC()
  {
    D res = new D();
    res.c = new C();
  }
  public void methodA()
  {
    if ( b!=null )
      b.methodA();
    else
      c.methodA();
  }
  public foid methodB() 
  {
    if ( b==null )
      throw new MethodNotImplementedException();
    else
      b.methodB();
  }
  public foid methodC()
  {
    if ( c==null )
      throw new MethodNotImplementedException();
    else
      c.methodC();
  }
}

Private inheritance has some drawbacks. 私有继承有一些缺点。 One is that D would not be an A. So you can't pass a D object as a parameter to a method which requires an A. This code would not compile : 一个是D不会是A.所以你不能将D对象作为参数传递给需要A的方法。这段代码不能编译:

void method( A a ) {...}

D d = D.instantiateAsB();
method( d );

You can work around that using cast methods in D's definition : 您可以使用D的定义中的强制转换方法来解决这个问题:

// inside D class :
public A castAsA()
{
  if ( b!=null )
    return (A)b;
  else
    return (A)c;
}

public B castAsB()
{
  if ( b==null )
    throw new ClassCastException();
  else
    return b;
}

public C castAsC()
{
  if ( c==null )
    throw new ClassCastException();
  else
    return c;
}

And the previous non compiling code would be rewritten as : 以前的非编译代码将被重写为:

D d = D.instantiateAsB()
method( d.castAsA() );

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

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