String或enum作为参数来引用模型字段

时间:2013-12-13 11:55:45

标签: java design-patterns enums

我有一种情况,我有一个模型有5个字段,包括getter和setter,比如说 id,name,age,dob,city

服务类包含一个方法,该方法必须仅返回数组形式的特定字段数据。就像我只想要所有人的名字和年龄一样。

List<Object> getEmpDataAsList(List<Object> fields);

所以我的方法看起来像这样,需要一个参数fields,其中包含需要返回的字段列表。因此,对于这种情况,我应该只将nameage发送到字段参数,并且我的getEmpDataAsList检测要求的字段并相应地构建返回数组。

我想知道最好的方法是什么。我应该将fields List作为字符串传递给我,目前我也在做,例如:

List<String> fields = new ArrayList<>();
fields.add("name");
fields.add("age");

getEmpDataAsList(fields);

但我认为,这不安全。如果我计划一天更改字段的名称或者如果我从模型中删除字段该怎么办,那么我需要在3个地方进行更改。我应该在模型类中创建枚举并使用枚举字段来创建相同的fields数组并使用它吗?或者还有其他更好的方法吗?

2 个答案:

答案 0 :(得分:1)

  

如果我计划在某一天更改某个字段的名称,或者如果我删除一个字段该怎么办?   从模型中的字段,然后我需要在3个地方进行更改。

这个问题没有解决办法。如果删除一个字段,它就会消失。您必须将其从模型和客户端中删除。但是这里有一个快速解决方案,可以明显改变,因此更改API会导致编译错误。

在编译时使用抽象父类中的泛型来检查参数列表:

public abstract class GenericDataInterface<KEY extends Enum> {
    public abstract Object getData(KEY key);

    public final List<Object> getEmpDataAsList(List<KEY> fields) {
        List<Object> result = new ArrayList<Object>(fields.size());
        for (KEY field : fields) {
            result.add(getData(field));
        }
        return result;
    }
}

示例模型类:

public class Pizza extends GenericDataInterface<Pizza.PizzaAttributes> {
    public enum PizzaAttributes { NAME, TOPPINGS, PRICE };

    private String name;
    private Set<String> toppings;
    // WARNING: Do not use Float for prices in real applications!
    private float price;

    @Override
    public Object getData(PizzaAttributes key) {
        switch (key) {
            case NAME:
                return name;
            case TOPPINGS:
                return toppings;
            case PRICE:
                return price;
            default:
                throw new IllegalArgumentException(
                        "Key " + key + " isn't defined for " + Pizza.class.getCanonicalName());
        }
    }
}

结果还不是很方便,因为按顺序扭曲会导致看不见的问题。因此,您可以使用地图作为结果

public abstract class GenericDataInterface<KEY extends Enum> {
    public abstract Object getData(KEY key);

    public final Map<KEY, Object> getEmpDataAsList(List<KEY> fields) {
        Map<KEY, Object> result = new HashMap<KEY, Object>(fields.size());
        for (KEY field : fields) {
            result.put(field, getData(field));
        }
        return result;
    }
}

您也可以使用实际模型类的克隆而不仅填充指定的属性,而不是Map。

进一步的想法:

  • 你真的需要这样的通用界面吗?
  • 如果是关于网络通信,你不能使用XML或JSON吗?

答案 1 :(得分:1)

您应该对不同的字段类型使用枚举。 (虽然,我不知道是否需要AGE和DOB,因为你可以计算当前日期和DOB的年龄......)

public enum Fields{
  NAME,
  DOB,
  CITY
   ...


 }

通过这种方式,您可以拥有更具意图的API。

List<Object> getEmpDataAsList(Fields...fields)

List<Object> getEmpDataAsList(Set<Fields> fields)

可以让你做像

这样的事情
results = getEmpDataAsList(Fields.AGE, Fields.DOB);

results = getEmpDataAsList(EnumSet.of(Fields.AGE, Fields.DOB));

如果您完全控制API,我建议您也将返回类型从List更改为Map,这样您就可以在不知道或不关心输入字段顺序的情况下知道哪个字段的值。

Map<Fields,Object> getEmpData(Fields...fields)

如果我计划在某一天更改某个字段的名称或者如果我从模型中删除字段会怎么样,那么我需要在3个地方进行更改。

使用枚举,如果重命名枚举,IDE可以为您自动重命名所有引用。如果删除枚举,则会出现编译器错误,因此您知道需要更改的内容。