我目前正在为我的Java项目开发协议处理程序。我正在尝试创建一个可维护和可扩展的API,这意味着我不想简单地对支持的值类型进行硬编码。
我已经开始设计一个“协议处理程序”,给定的值(受支持的类型)可以根据协议的规范对该值进行编码,而客户不必担心翻译过程的细节。
不同的值类型,例如字符串或整数必须具有不同的编码过程,但是我不希望客户担心为它们可能需要编码的每种可能的类型持有对不同对象的引用-正如我说的那样,我不想让他们担心细节。
到目前为止,我已经定义了一个“通用” DynamicHandler类,该类维护“特定”类型感知的StaticHandlers的集合:
class DynamicHandler
{
Map<Class, StaticHandler> handlers;
<T> void handle(T value)
{
if(handlers.containsKey(value.class))
handlers.get(value.getType()).handle(value);
}
void <T> register(StaticHandler<T> handler)
{
handlers.put(T.class, handler);
}
}
此类的思想是,客户端只需将要编码的值传递给handle方法,然后DynamicHandler就会查找并委托给StaticHandler。
interface StaticHandler<T>
{
void handle(T value);
}
以下是使用此系统的某些客户端的示例:
class StringHandler implements StaticHandler<String>
{
void handle(String value)
{
...
}
}
DynamicHandler handler = new DynamicHandler();
handler.register(new StringHandler());
handler.handle("Hello World!");
我有两个问题要自己寻找答案:
DynamicHandler.register
方法中,如何在没有T实例的情况下获得T的类型?编辑:由于DynamicHandler本质上是一个Map,尽管正在进行一些通用的欺骗,但是否可以将其实现为:DynamicHandler implements java.util.Map<...,...>
(我不确定在这里应该使用什么Key和Value类型)
这是我第一次在这里问一个问题,所以我希望我对所有人都足够清楚。如果您认为有任何需要澄清的地方,请告诉我,我会尽力而为。
答案 0 :(得分:0)
- 在DynamicHandler类中,如何在没有T实例的情况下获取T的类型?
常见的解决方案是向其传递一个Class
对象:
void <T> register(StaticHandler<T> handler, Class<T> clazz)
{
handlers.put(clazz, handler);
}
就像在一个常用库中的一个例子:Gson做的事情类似,用GsonBuilder.registerTypeHierarchyAdapter
答案 1 :(得分:0)
如果未处理null
值,并且设计该值使得永远不会有属于多个类的任何值,那么您可以这样做:
public class DynamicHandler {
Map<Class, StaticHandler> handlers;
public <T> void handle(T value) {
if(value != null) {
handlers.entrySet()
.stream()
.filter(entry ->
entry.getKey().isInstance(value))
.findAny()
.ifPresent(entry ->
entry.getValue().handle(value));
}
}
public void <T> register(StaticHandler<T> handler) {
handlers.put(handler.getHandlingClass(), handler);
}
}
interface StaticHandler<T>
{
void handle(T value);
Class<T> getHandlingClass();
}
public class StringHandler implements StaticHandler<String> {
@Override public void handle(String value) {
...
}
@Override public final Class<String> getHandlingClass() {
return String.class;
}
}