在Java中将String转换为不同类型的好设计

时间:2017-09-25 21:46:59

标签: java design-patterns

我有一个类Data,它以String的形式存储单个数据,它还存储应该转换此数据的类型,该类型存储为枚举常量(仅允许用于specyfic类型)。描述一个项的数据对象存储在DataItem类中。意图是Data对象对应于表中的字段,DataItem表示完整行。同样重要的是要提到Data对象是从DataTemplate类创建的,它指定在何处查找此类数据及其类型(因此每个Data的类型应在编译时知道)。

我希望这个程序在数据库选择方面非常灵活,所以方法" save"来自存储接口,允许在实现后使用任何类型的存储(文件/ RDB /文档数据库......)。

我想知道将这些String值从Data对象转换为适当类型的好方法,这样我就可以将它们保存到数据库中。一种简单的方法是使用这样的东西:

public void save(DataItem dataItem) {
    for (Data data : dataItem) {
        if (data.getType() == DataType.BOOLEAN) {
            // Convert to String to boolean and save
        }
        else if (data.getType() == DataType.DOUBLE) {
            // Convert to String to double and save
        }
        ...
    }
}

但它不是一个非常好的设计,因为我必须为每个save实现重复这个代码。它也违反了开放/封闭原则,因为如果我添加一些新类型,我将不得不修改所有保存方法。

我也尝试过使用泛型或反射,但这些实现都没有令人满意。

我想出的一个通用解决方案要求用户使用提供的枚举常量之一,然后不是存储枚举常量,Data类将存储相应类型的Class实例。这样我就可以控制可以使用的类型,并在选择错误的类时获得编译时错误。这将允许我实现以这种方式工作的转换器方法。

public <T> T convert(Data data, Class<T> clazz) {
    if (data.getType() == Boolean.class) {
        // Convert String to Boolean
        return (T) 
    }
    else if (data.getType() == Double.class) {
            // Convert to String to Double
            return (T)
    }
    ...
}

然后我还可以在DataType枚举中使用类似的模式和存储转换方法以及允许的数据类型。使用每种类型必须指定的抽象方法。类似的东西:

public enum DataType {
    BOOLEAN(Boolean.class){
        @Override
        public <T> T convert(Data data, Class<T> clazz) {
            return clazz.cast(Boolean.parseBoolean(data.getContent()));
        }
    },
    DOUBLE(Double.class){
        @Override
        public <T> T convert(Data data, Class<T> clazz) {
            return clazz.cast(Double.parseDouble(data.getContent()));
        }
    },
    ...;
    ...
    public abstract <T> T convert(Data data, Class<T> clazz);
}

在这种情况下,我只需要在添加新类型时修改DataType枚举,前提是底层存储具有接受所有允许类型的方法。

最后,我的问题: 1.有更好的方法吗? 2.如果不是,我应该选择哪种设计?

2 个答案:

答案 0 :(得分:0)

您可以创建一个接口(Savable),每个可保存的类需要使用名为toSaveString和initFromSaveString的2个接口函数来实现。

然后,当从DB加载时,您只需要switch语句来确定将数据加载到哪个类。

答案 1 :(得分:0)

您可以将转化功能存储在Map<Class<?>,Function<String,?>>地图中。根据{{​​1}}查找转化函数。在创建新类型时向地图添加新功能。

Class

或者,您可以创建自己的Map<Class<?>,Function<String,?>> map = new HashMap<>(); <T> T convert(String data, Class<T> clazz) { return (T) map.get(clazz).apply(data); } 类,并为每种类型创建 singleton 实例,并为每个单例添加适当的转换方法:

DataType

您可以根据需要向public abstract class DataType<T> { <T> T fromString(String data); } public final static DataType<Boolean> BOOLEAN = new DataType<Boolean>() { Boolean fromString(String data) { ... } }; // ... Data data = ... Object value = data.getType().fromString(data.getContent()) 添加其他字段和方法。