6

我正在为用户偏好创建一个商店,并且用户可以设置固定数量的偏好值。首选项(设置)的名称存储为枚举:

public enum UserSettingName {

    FOO,
    BAR,
    ETC

}

我想要做的是存储带有名称的值类型,以便服务将使用正确的 Java 类型存储用户的值。例如, FOO 可能是Long,而 BAR 可能是String。到目前为止,我们将所有值存储为Strings,然后手动将值转换为适当的 Java 类型。这导致到处都有 try/catch 块,而在服务中只有一个 try/catch 更有意义。我知道枚举不能有泛型类型,所以我一直在玩:

public enum UserSettingName {

    FOO(Long.class),
    BAR(String.class),
    ETC(Baz.class)

    private Class type;

    private UserSettingName(Class type) {
        this.type = type;
    }

    public Class getType() {
        return this.type;
    }
}

我有一个通用的 UserSetting 对象,它具有应该返回并设置正确类型的值的方法public T getSettingValue()public void setSettingValue(T value)我的问题来自于T在创建或检索设置时尝试指定该泛型类型,因为我无法执行以下操作:

new UserSetting<UserSettingName.FOO.getType()>(UserSettingName.FOO, 123L)

抱歉,如果这不是很清楚,如果不理解,我可以尝试澄清。

谢谢!

更新

设置名称和值都来自 Spring MVC REST 调用:

public ResponseEntity<String> save(@PathVariable Long userId, @PathVariable UserSettingName settingName, @RequestBody String settingValue)

所以我使用了 Enum,因为 Spring 会自动转换传入的数据。

4

3 回答 3

3

首先,您必须退后一步,思考您想要实现的目标,并使用标准模式或语言结构来实现它。

目前尚不完全清楚您要在这里追求什么,但从您的方法来看,几乎可以肯定的是,您正在重新发明一些可以在 Java 中以更直接的方式完成的东西。例如,如果您确实需要了解和使用对象的运行时类,请考虑使用反射 API。

在更实际的层面上 - 你在这里尝试做的事情对于泛型是不可能的。泛型是一种编译时语言特性——它们对于避免从 Object 显式转换所有内容以及在编译时为您提供类型检查非常有用。您根本不能以这种方式使用泛型,即设置为仅在运行时才知道的T某个值。UserSettingName.Foo.getType()

于 2013-10-14T22:12:46.253 回答
2

看看netty是怎么做的:

http://netty.io/wiki/new-and-noteworthy.html#type-safe-channeloption

他们通过使用类型化常量来做到这一点:

http://grepcode.com/file/repo1.maven.org/maven2/io.netty/netty-all/4.0.0.Beta1/io/netty/channel/ChannelOption.java#ChannelOption

编辑:

public interface ChannelConfig {
   ...
   <T> boolean setOption(ChannelOption<T> option, T value);
   ...
}

public class ChannelOption<T> ...
    public static final ChannelOption<Integer> SO_TIMEOUT =
        new ChannelOption<Integer>("SO_TIMEOUT");
    ...
}

EDIT2:您可以将其转换为:

class Baz {}

class UserSettingName<T> {
    public static final UserSettingName<Baz> ETC = new UserSettingName<Baz>();
}

class UserSetting {
    public <T> UserSetting(UserSettingName<T> name, T param) {

    }
}

public class Test {
    public static void main(String[] args) {
        new UserSetting(UserSettingName.ETC, new Baz());
    }
}
于 2013-10-14T22:02:46.637 回答
0

枚举不是这里的答案。如果您发现自己到处重复代码,您可以创建一个实用程序类并在那里封装所有的 try/catch 逻辑。这将减少您的代码冗余,而不会对您当前的代码产生重大影响。

public class Util
{
    public static MyObject getObjectFromString(String s)
    {
        try
        {
            return (MyObject)s;
        }
        catch(Exception e)
        {
            return null;
        }
    }
}

然后使用如下:

MyObject myObj = Util.getObjectFromString(string);
于 2013-10-14T22:29:16.803 回答