Java &引用;“价值”;成员字段可以是四种不同类型之一-最佳设计?

Java &引用;“价值”;成员字段可以是四种不同类型之一-最佳设计?,java,design-patterns,model,Java,Design Patterns,Model,我有一个叫做“DataModel”之类的类,它基本上是一个数据单元,可以是字符串、数字、日期或具有各种(相同)属性的布尔值 编写此模型的最佳方式是什么 使值的类型为Object interface DataModel { Object getValue(); // cast to whatever is needed int getValueType(); // uses four constants } 有四个不同的实现“StringModel”、“NumberModel”等

我有一个叫做“DataModel”之类的类,它基本上是一个数据单元,可以是字符串、数字、日期或具有各种(相同)属性的布尔值

编写此模型的最佳方式是什么

  • 使值的类型为Object

    interface DataModel {
       Object getValue();  // cast to whatever is needed
       int getValueType(); // uses four constants
    }
    
  • 有四个不同的实现“StringModel”、“NumberModel”等,每个实现都有自己的类型化“getValue()”方法。这意味着如果您有一个数据模型,那么您必须转换到正确的模型才能获得值

    interface DataModel {
       int getValueType();
    }
    interface NumberDataModel extends DataModel {
      Integer getValue();
    }
    ...
    
  • 有四种不同的方法,每种方法在调用错误的值类型时都会引发异常:

    interface DataModel {
      String getStringValue();
      Integer getIntegerValue();
      ...
      int getValueType();
    }
    
  • 使用泛型。这有一个缺点,理论上我可以拥有任何类型的任何对象…另一方面,如果T不是4种允许的类型之一,我可以在构造函数中抛出一个IllegalStateException

    interface DataModel<T> {
      T getValue();
    }
    
    接口数据模型{
    T getValue();
    }
    
  • 没关系。以上任何一项。;)


  • 4似乎是最好的-即使您不想实现任何旧类型,也没有特别的理由不应该在理论上允许它-它不会干扰您正在做的任何其他事情。

    1是好的,如果您不打算添加许多/任何新类型,并且您不需要允许第三方添加自己的类型。我可能会使用枚举而不是int

    我不认为做2比4有什么好处。4是泛型的,但您可能希望在泛型中包含getValueType(),以便让代码在运行时查询该类型,这通常很有用

    我不认为3是正确的方法,除非您的模型的内容支持以不同的方式检索(就像JDBC那样),但我不认为这里是这样

    根据过去的经验,我将执行4,并将getValueType()添加到其中。

    以上都没有

    由于您需要了解类以对getValue()的结果进行合理的处理,因此在本例中,使用包含类似getValue()的方法的公共接口没有任何好处


    创建一个包含公共部分的基类,然后创建子类并添加所需的内容。您可以使用instanceof而不是getValueType(),但如果您确实需要getValueType,则可以将其作为抽象方法添加到基类中。如果使用getValueType,我建议它返回一个枚举,而不是int。

    4是最好的答案。您将获得灵活性和便利性

    另一方面,如果您真的想限制类型,可以使用4和2的组合。像这样:

    interface DataModel<T> {
       T getValue();
    }
    interface NumberDataModel extends DataModel<Number> {
       // empty
    }
    class NDM implements NumberDataModel {
       Number getValue() { return ... }
    }
    
    接口数据模型{
    T getValue();
    }
    接口编号DataModel扩展了DataModel{
    //空的
    }
    类NDM实现NumberDataModel{
    Number getValue(){return…}
    }
    

    然后,您可以将DataModel接口设置为受保护/默认。

    作为一般替代方案,您可以使用和获取数据元素的类型安全实例。这允许通过通用参数进行编译时检查,并通过运行时检查。

    有很多用例可以使用公共接口对它们进行分组。需要在整个值集合上聚合操作的任何位置,如在验证一组数据项时,类型可能不同。在执行普通操作时,可以参考超类。我对答案稍加修改,以明确我的意图。当然,您可以添加一个包含基类的所有公共方法的接口,但除非您想用一个新类来实现该接口,否则我认为这样做没有什么用处。我认为这就是泛型版本的工作原理,因为泛型的全部要点是避免为每种可接受的数据类型创建一个类,并且在编译时强制执行类型安全性。如果使用泛型版本,那么一个集合中不能有多个DataModel实例。@Buhb:没有人在集合中谈论DataModel这是您的最终答案吗?:)选择取决于类的用途。我们能举几个小例子吗?我现在可以告诉你的一件事是,答案不是3。