【发布时间】:2025-12-16 16:00:02
【问题描述】:
我有一个TemplateEngine 接口,其实现将是MoustacheTemplateEngine、FreemarkerTemplateEngine 等。
public interface TemplateEngine<T> {
public T compileTemplate(String templateStr);
public void merge(T t, Map<String, Object> data);
public String getTemplateLang();
}
compileTemplate 方法的目的是启用已编译模板的缓存。
这是一个实现示例:
import com.github.mustachejava.Mustache;
public class MoustacheTemplateEngine implements TemplateEngine<Mustache> {
@Override
public Mustache compileTemplate(String templateStr) {
// return compiled template;
}
@Override
public void merge(Mustache compiledTemplate, Map<String, Object> data) {
// merge
}
@Override
public String getTemplateLang() {
return "moustache";
}
}
我希望创建一个根据提供的模板语言返回TemplateEngine 的工厂。 工厂和使用工厂的客户对TemplateEngine 实现一无所知。
public class TemplateEngineFactory {
private Map<String, TemplateEngine<?>> TEMPLATE_ENGINE_REGISTRY = new HashMap<>();
@PostConstruct
public void init() {
// Scan all TemplateEngine impls in classpath and populate registry
}
public TemplateEngine<?> getTemplateEngine(String templateLang) {
return TEMPLATE_ENGINE_REGISTRY.get(templateLang);
}
}
客户将使用以下工厂。
Map<String, Object> data = new HashMap<>();
data.put("name", "Tom");
TemplateEngine<?> templateEngine = factory.getTemplateEngine("moustache");
Object compiledTemplate = templateEngine.compileTemplate("Hi {{name}}");
templaeEngine.merge(compiledTemplate, data); // compile error
错误是The method merge(capture#3-of ?, Map<String,Object>) in the type TemplateEngine<capture#3-of ?> is not applicable for the arguments (Object, Map<String,Object>)。
我了解该错误,并且我知道我的 API 设计存在缺陷,因为在工厂中使用了通配符。我的问题是如何为这种用例设计工厂并避免不安全的演员表?
【问题讨论】:
-
你为什么不输入你的
TemplateEngineFactory?因此,当您实例化一些您想要的实现时,而不是使用通配符,调用TemplateEngine的任何方法都不会有任何问题。 -
也许您也应该考虑将具体的模板实现(例如
Moustache)隐藏在一个通用接口后面? -
@yegodm 是的,但这并不能解决问题,因为我想避免在
merge方法中对编译后的模板进行类型转换。 -
也许您也可以将
merge()委托给该接口? -
@yegodm 在我得到正确的泛型之前,我仍然需要使用不安全的强制转换。