【问题标题】:Java class property that can support different types可以支持不同类型的 Java 类属性
【发布时间】:2016-09-26 06:15:59
【问题描述】:

我正在用 Java 构建一个内容管理系统,我有一个表示实体的类和一个表示实体内的字段的类。

目前我的 Field 类作为 String 的数组列表来存储所有值。

我的班级是这样的:

public class Field implements Serializable {
    private UUID key;
    private String name;
    private ArrayList<String> values;
    private Integer maxValues;
    private ValueType type;
    private String code;

    public enum ValueType {
        INT,
        VARCHAR,
        DATE,
        BOOLEAN
    }

    public void addValue(String value){
        if (this.values.size() < this.maxValues){
            this.values.add(value);
        }
    }

    public ArrayList<String> getValues(){
        return this.values;
    }
}

我想存储字符串、整数、浮点数和日期,我想我可以在输入值时对它们进行类型检查,并有单独的方法将这些值作为正确的类型来获取。

public ArrayList<Integer> getIntegerValues(){

    ArrayList<Integer> integerValues = new ArrayList<Integer>();


    values.forEach(
        (v) -> {

            Integer intValue = Integer.parseInt(v);

            integerValues.add(intValue);

        }
    );

    return integerValues;
}

我认为这可行,但感觉不是一个很好的解决方案,因为在使用此类时,您必须选择正确的函数来获取类型。如果只有一个函数可以返回正确的版本,那就太好了。

有没有人知道我怎样才能写得更好。

【问题讨论】:

  • 看起来你想使用泛型
  • 一个字段可以包含多个类型吗?
  • 没有一个字段永远不会包含不同的类型。

标签: java types


【解决方案1】:

这是一个如何使用泛型的示例:

public class Field<T> implements Serializable {
    private UUID key;
    private String name;
    private ArrayList<T> values;
    private Integer maxValues;
    private String code;

    public void addValue(T value) {
        if (this.values.size() < this.maxValues){
            this.values.add(value);
        }
    }

    public ArrayList<T> getValues(){
        return this.values;
    }
}

【讨论】:

  • 我喜欢这个想法,我认为它会解决我的问题,但同时引入另一个问题,返回时不知道类型,我想我会在添加值时执行严格的类型检查字段对应对象类型。
  • 你应该知道类型。当你定义一个字段时,你会将它定义为 Field 并且你放在那里的任何类型都将是返回的类型。
【解决方案2】:

更多的是另一种观点:如果您得出泛型在这里对您没有帮助的结论 - 您仍然应该将枚​​举用于此类事情。

枚举的问题在于:它们对于将来更改的可能性很小的“模型”非常有帮助。因为通常发生的情况是:对于您拥有的每个枚举,您将创建 switch 语句;为了为您的不同枚举常量实现不同的行为。这听起来可能不是问题,但它是......当你意识到你需要添加 another 类型。然后你必须找到所有这些开关并决定如何处理新的枚举常量。

相反,您的设计应该由Open/Closed principle 驱动:开放 以进行更改;但关闭进行修改。在 OO 中,这通常转化为使用抽象类,例如

public abstract class ValueType {
  ... which has some ABSTRACT methods
  ... and probably some FINAL methods

抽象方法是您实现不同子类的行为的地方;最终方法是那些“修复”该行为的方法,对于此类的每个实例都应该是相同的。

然后您继续创建特定的子类,例如IntValue extends ValueType 等等。

为什么这样更好?非常简单:添加一种新的 ValueType 意味着......创建一个新的子类 - 无需触及任何现有代码。因此,这样的设计对于更改(添加新类型!)是开放,但对于修改封闭(因为添加新类型不会改变其他现有类中的任何内容)。

【讨论】:

  • 我很喜欢这个想法,可以强制在构造函数中添加一个ValueType,但是如果抽象方法addValue和getValue需要使用泛型?
  • 虽然我检查了泛型的答案是正确的,但我已经编写了泛型实现的代码,我发现它不是最好的解决方案,它违反了你提到的开放封闭原则,我认为 Field 类可能需要抽象,所以会有一个 VarcharField / IntegerField / FloatField 扩展 Field,将尝试实现,看看感觉如何,但在我看来,它似乎会在设计中提供更大的灵活性,更容易添加新类型。
  • 很高兴您发现我的意见很有帮助。如果可能的话,我建议你和一些有经验的人面对面交谈;这样的问题只需要大量的思考;和思想交流通常会有所帮助。
【解决方案3】:

我对任何一个答案都不是 100% 满意,也不是解决这个问题的正确方法,两种方法都有问题需要处理。但是我意识到两个答案一起会给出一个很好的解决方案,所以感谢两者。

您的具体类将定义通用值的值。这将满足开放封闭主体。

public interface FieldType<T> {
    void addValue(T value);
    ArrayList<T> getValues();
}

public abstract class Field<T> implements FieldType<T>, Serializable {
    private UUID key;
    private String name;
    protected ArrayList<T> values;
    private Integer maxValues;
    private String code;

    public abstract void addValues();

    public ArrayList<T> getValues(){
        return this.values;
    }
}

public class FloatField extends Field<Float> {

    @Override
    public void addValue(Float value) {
        this.values.add(value);
    }

    @Override
    public ArrayList<Float> getValues() {
        return this.values;
    }
}

【讨论】:

    猜你喜欢
    • 2020-01-16
    • 1970-01-01
    • 2019-03-17
    • 2018-08-11
    • 1970-01-01
    • 1970-01-01
    • 2019-09-12
    • 1970-01-01
    相关资源
    最近更新 更多