【问题标题】:Subclassing generic - constructor inheritance子类化泛型 - 构造函数继承
【发布时间】:2018-12-22 15:27:16
【问题描述】:

我正在尝试为变量表示创建一个类,所以我首先创建了一个参数化基类:

public abstract class DataField<Type>
{

    public enum DataTypes
    {
        STRING,
        INT,
        FLOAT,
        TIME,
        DATE
    }

    private DataTypes type=null;
    private String name=null;
    private Type value=null;

    private DataField()
    {
    }

    public DataField(String name)
    {
        setName(name);
    }

    DataField(String name, DataTypes type)
    {
        this(name);
        setType(type);
    }

    DataField(String name, DataTypes type, Type value)
    {
        this(name, type);
        setValue(value);
    }

    public DataField(String name, Type value)
    {
        this(name);
        setValue(value);
    }
    public DataField(String name, String value)
    {
        this(name);
        setStringValue(value);
    }
    public abstract void setStringValue(String strValue);
     ...
}

然后为不同类型制作子类,定义方法:

public class DataFieldInt extends DataField<Long>
 ...
public class DataFieldBoolean extends DataField<Boolean>
 ...

等等。但我对字符串有一个预期的问题: 通用超类有 2 个构造函数 DataField(String name, Type value) 设置变量的名称和值,以及 DataField(String name, String value) 从 String 中设置变量的名称和值,将其转换为所需的类型。但是对于子类,我有一个问题 - 使用什么构造函数,因为它们都是(字符串,字符串)。所以,这段代码

public class DataFieldString extends DataField<String>
{
    public DataFieldString(String name, String value)
    {
        super(name, value);
           ...
    }

给出关于模糊引用的错误 如何解决?我看到的唯一方法是使用 StringBuilder 或 StringBuffer 之类的东西来代替 String,但有趣的是,有没有“原生”解决方案?

谢谢

【问题讨论】:

  • 你可以使用静态工厂方法代替构造函数
  • 当然,工厂模式等等。但有趣的是如何在这里使用构造函数。我一直想知道 java oop 尤其是在多年的 c++ 经验之后,但在这种情况下,我不知道如何解决这个问题
  • 好吧,又看了一遍,没看懂——这种情况下如何使用工厂模式?你的意思是根本不使用构造函数?

标签: java generics inheritance constructor


【解决方案1】:

如何解决?

通过提供对编译器没有任何歧义的调用。

我看到的唯一方法是使用类似 StringBuilder 或 StringBuffer 代替了String,不过有意思的是,有没有一个 “原生”解决方案?

它会起作用,但是依靠 String 的构建器 来传达不需要构建的 String 也显得笨拙。

cmets 中建议使用Factory 的想法还不错,但根据您的设计,我认为这将需要进行许多更改并使您脱离实际设计:依赖于基础的类层次结构上课。
因为要使类之间的内容保持一致,您应该在每个子类中定义工厂。
此外,如果您将两个构造函数保留在基类中,它不会解决您的歧义问题。因此,您可能应该允许子类访问基类字段以执行构造函数逻辑。

因此,为了符合您的实际设计,我将通过引入一个包装 TypeString 变量的新类来解决歧义问题。
你可以在DataField 类中声明这个类:

static class NameAndType<Type> {
    private String name;
    private Type value;
    public NameAndType(String name, Type value ){
       ....
    }
}

所以DataField 类可以公开这两个构造函数:

public DataField(NameAndType<Type> nameAndType) {
    this(nameAndType.name);
    setValue(nameAndType.value);
}

public DataField(String name, String value) {
    this(name);
    setStringValue(value);
}

通过这种方式,您可以在DataFieldString 中公开一个依赖于基类构造函数之一的构造函数:

public class DataFieldString extends DataField<String> {

    public DataFieldString(String name, String value) {
        super(name, value);
        //  or the other way : super(new NameAndType<>(name, value));
    }    
   ...
}

其他子类可以提出两个依赖于基类构造函数的构造函数。
例如:

public class DataFieldInt extends DataField<Integer> {

    public DataFieldInt(String name, Integer value) {
        super(new NameAndType<>(name, value));
    }

    public DataFieldInt(String name, String value) {
        super(name, value);
    }

    ...
}

并且NameAndType 复杂性/使用对这些类的客户不可见:

DataFieldInt dataFieldIntOne = new DataFieldInt("var1", 321);
DataFieldInt dataFieldIntTwo = new DataFieldInt("var1", "321");
DataFieldString dataFieldString = new DataFieldString("var1", "321");

【讨论】:

  • 当然,可以通过提供明确的调用来解决不明确的调用,我完全同意! )) 是的,关于工厂模式并使用另一种类型而不是 String - 这正是我的想法,我不喜欢第二种解决方案,也不明白第一种解决方案如何轻松实现。新的包装类 - 太复杂了,我们的想法是让它更简单。我想让它可以只使用简单的new DataFieldInt("var1", 321)new DataFieldInt("var1", "321") 最后我可以使用包装的字符串,所以只有这个特殊的情况会被包装......虽然不好。
  • 类的客户可以写new DataFieldInt("var1", 321)new DataFieldInt("var1", "321")。事情对客户来说很简单。我更新以说明。
  • 嗯,终于明白你的意思了。删除构造函数/用另一个替换它是相同的。好的,我可以将它从基类中删除,然后替换为另一个,例如使用不同的参数。
  • 我实际上删除了这个构造函数,而是留下了另一个带有 3 个参数的构造函数,包括类型。几乎相同,但没有内部类。谢谢!
猜你喜欢
  • 1970-01-01
  • 2020-09-11
  • 1970-01-01
  • 2019-02-20
  • 1970-01-01
  • 1970-01-01
  • 2015-03-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多