通用父类扩展器

问题描述 投票:0回答:1

我有2个父类和一个子类,我正在尝试使这个流程工作(请注意,我知道还有其他解决方法之类的,但我并没有尝试在构造函数和其他东西中初始化变量,这只是概念证明):

public class Child{
    String testVar1;
}

public class ParentA extends Child{
    String testVar2;
}

public class ParentA extends Child{
    Boolean testVar3;
}

我也有这样的方法:

public Child createChild(){
    return new Child("testString")
}

// the method being called ▼ ▼ ▼ ▼
public ParentA createParentA(){
    return (ParentA) createChild();
}

public ParentB createParentB(){
    return (ParentB) createChild();
}

这当然会失败,因为您无法通过类型转换子类来实例化父类。我试图使父类中所有未调用的变量都变为 null,因此在这种情况下,应该创建一个如下所示的对象:

{
    testVar1 = "hello",
    testVar2 = null
}

我也有一个想法,我们会做这样的事情:

public <T> T createChild(Class<T> parentclass){
    return (parentClass) new Child("testString")
}

// the method being called ▼ ▼ ▼ ▼
public ParentA createParentA(){
    return createChild(ParentA.class);
}

public ParentB createParentB(){
    return createChild(ParentB.class);
}

我知道这不是正确的编码方式,但你明白我想要做什么。有什么办法可以让方法直接转换到父类吗?

java spring-boot lombok
1个回答
0
投票

这听起来绝对像一个 XY 问题。因为你的请求很奇怪:真的很难想出合理的用例这种思路会导致最好的答案。很容易想到这是一种解决方案,而不是一个很好的解决方案 - 其他解决方案会更好。因此,您很可能处于第二种情况,您应该退后一步并解释根本问题。

在不太可能的情况下,你真的想走这条路:

有 3 种不同的方法来解决这个问题。

具有对构造函数的反射访问

您必须在子类中创建构造函数(请注意,在您的示例中,您已将超类命名为

Child
,将子类命名为
Parent
。这恰恰是错误的方法!为了避免混淆,我将使用术语“超类”和“子类”,但是,实际上,通常来说,它是
class Parent {}
class Child1 extends Parent {}
class Child2 extends Parent {}
(通俗地说)。

这些构造函数必须接受超类型的实例,并且它将复制所有相关字段,并将其余字段设置为所需的默认值:

public class Super {
    String testVar1;

    public Super(String testVar1) {
      this.testVar1 = testVar1;
    }
}

public class SubA extends Super {
    String testVar2;

    public SubA(Super s) {
      super(s.getTestVar1());
      this.testVar2 = "";
    }
}

public class SubB extends Super {
    boolean testVar3;

    public SubB(Super s) {
      super(s.getTestVar1());
      this.testVar3 = false;
    }
}

作为主题的细微变化,您的

Super
类也可以有一个构造函数,该构造函数采用
Super
的实例并复制它可以复制的所有内容。如果
Super
具有很多属性,则特别有用。

构造函数的问题是:它们完全存在于分层类型系统之外。定义接口或以任何其他方式暗示给定类具有特定构造函数是不可能的。因此,你被迫使用反射,如果有人写了一个错误(不遵守约定),你直到运行时才会知道。换句话说,该系统要求所有子类型都有这样的构造函数,但如果您编写一个没有这样的子类型,则不会收到任何编译时警告或错误: static <T> T create(Class<T> type, Super base) { return type.getConstructor(Super.class).newInstance(base); }

工厂

java 拥有大量工厂是有原因的:它们是解决静态方法和构造函数不属于分层类型系统的问题的方法。工厂通过添加一层来解决这个问题:工厂是一个对象的实例,它的一个方法创建它作为工厂的事物的实例。这样,“make a thing”方法是一个实例方法,

do

参与打字系统,因此,您可以为它创建一个接口: public interface FooFactory<F extends Super> { F create(Super base); } // Super, SubA and SubB are essentially just as above. public class SubAFactory implements FooFactory<SubA> { public static final SubAFactory INSTANCE = new SubAFactory(); @Override public SubA create(Super base) { return new SubA(base); } }

这是一些额外的代码,但现在不再需要搞乱反射,并且任何违反设置的行为(例如没有该构造函数)现在
都会导致编译时错误,这很好。如果你的情况真的这么简单,代码也可以非常简单:

public class SubA extends Super { // all the stuff as above. And also... public static final FooFactory<SubA> FACTORY = SubA::new; }

那一行就是您所需要的。
龙目岛

我注意到你用 lombok 标记了这个问题。这感觉有点像样板文件,所以你可能会想:嗯,我想知道 lombok 是否可以生成这些工厂或反射“构造函数”。

不。这不是“常见”的样板。这不是我所知道的任何问题的通用解决方案。只有

通用样板

才是获得 Lombok 项目关注的候选者。

来源:我是决定 lombok 做什么的身体的 50%。

© www.soinside.com 2019 - 2024. All rights reserved.