我目前有多个类,即FacadeA
... FacadeZ
,它们扩展了FacadeBase
。 FacadeBase
应该具有(某种通用方法?),即checkFacade
,它将引发扩展FacadeAException
的异常FacadeZException
... FacadeException
。>
这是我目前所了解的。我坚持使用通用部分(或任何可以解决我的问题的方法)。
是的,我知道我无法实例化示例中编写的泛型。
public abstract class FacadeBase {
public void checkFacade(final String facadeId) throws Facade<A...Z>Exception {
if (!isFacadeAvailable(facadeId)) {
throw new Facade<A...Z>Exception(facadeId);
}
}
...
}
public class FacadeA extends FacadeBase {
public void doSomethingWithFacadeA(final String facadeId) throws FacadeAException {
checkFacade(facadeId));
...
}
}
public class FacadeAException extends FacadeException {
private FacadeAException(final String message) {
super(message);
}
}
public abstract class FacadeException extends Exception {
private FacadeException(final String message) {
super(message);
}
}
答案 0 :(得分:2)
您可以使用泛型,但这还不够,因为您需要在运行时实例化特定类型。
大致来说,您有两种方法:
1)反射方式并不简单。 Java不能提供您所需的全部功能。您可以从Spring启发或使用像Spring这样的库。
org.springframework.core.GenericTypeResolver
应该特别对您有帮助。
您可以使用static Class<?> resolveTypeArgument(Class<?> clazz, Class<?> genericIfc)
方法:
解析给定通用接口的单一类型参数 针对给定的目标类别(假定实现该目标类别) 通用接口,并可能为其类型声明一个具体类型 变量。
如:
public abstract class FacadeBase<T extends FacadeException> {
private final Class<T> genericClazz;
public FacadeBase () {
this.genericClazz = (Class<T>) GenericTypeResolver.resolveTypeArgument(getClass(), FacadeBase.class);
}
}
现在,您可以使用genericClazz.newInstance()
或更佳的Constructor.newInstance()
实例化泛型的类。
2)声明方式更简单,但是需要一些样板代码。
使您的抽象类成为通用类,该通用类指定异常类型并提供一个存储要抛出的异常的构造函数。
例如:
public abstract class FacadeBase<T extends FacadeException> {
private Supplier<T> suppException;
public FacadeBase(Supplier<T> suppException) {
this.suppException = suppException;
}
public void checkFacadeAvailability(final String facadeId) throws T {
if (!isFacadeAvailable(facadeId)) {
throw suppException.get();
}
}
}
子类应该使用其供应商来调用超级构造函数:
public class FacadeA extends FacadeBase<FacadeExceptionA>{
public FacadeA(Supplier<FacadeExceptionA> suppException) {
super(suppException);
}
}
作为替代方案,您可以将Supplier
替换为Class
参数,但总体思路是相同的。
答案 1 :(得分:1)
有两个很好的理由停在throws FacadeException
:
FacadeBase.checkFacade
的合同总会迫使客户抓住FacadeException
(假设进行接口编程的良好做法)Exception
子句中使用throws
类型的参数,但这只是过度设计(除了违反最佳实践)因此,子类应声明throws Facade<A...Z>Exception
或完全忽略此子句(如果适用)。但这对客户端/调用者没有任何影响(除非他们采取不鼓励使用的声明子类类型的方法)
如果您需要检查在呼叫方出现的 异常,那么无论如何您都必须知道具体的异常类,因为您无法检查{{1 }}。
答案 2 :(得分:1)
据我所知,问题的核心是如何按照此伪代码示意表示的方式声明和实现checkFacade()
方法:
public abstract class FacadeBase { public void checkFacade(final String facadeId) throws Facade<A...Z>Exception { if (!isFacadeAvailable(facadeId)) { throw new Facade<A...Z>Exception(facadeId); } } ... }
我首先注意到,将 characteristic 异常与具体的FacadeBase
子类相关联会破坏抽象。子类当然可以抛出自己的特定异常,但是一旦其他类特别了解或关心这些异常,尤其是为了能够识别那些子类,抽象就会崩溃。
特别是,如果您的isFacadeAvailable(facadeId)
方法与Java类路径中可用的FacadeBase
子类有任何关系,那么这似乎与该Facade实现的典型异常可用相关。在那种情况下,当FacadeQException
不可用时,您不能期望能够实例化FacadeQ
,并且当在类路径中不存在任何异常时,很可能会遇到类加载失败。 / p>
第二,我注意到由于所有Facade[A-Z]Exception
都扩展了FacadeException
,FacadeBase.checkFacade()
可以简单地声明FacadeException
而不是声明所有单独的异常。如果确实仍然由该方法抛出异常,那将不会阻止其他代码捕获特定异常。
要实际抛出各个异常,您需要先构建它们,这需要大switch
块,大if
/ then
/ {{ 1}}语句,工厂方法或适当的异常类的反射实例化,或它们的某种组合。请注意,异常是对象;可以将它们分配给变量并从方法中返回。 else
语句可以抛出 any throw
;它不必是新实例化的。因此,您可以考虑以下几点:
Throwable
但是,我敦促您考虑给public void checkFacade(final String facadeId) throws FacadeException {
if (!isFacadeAvailable(facadeId)) {
throw createFacadeException(facadeId);
}
}
private FacadeException createFacadeException(String facadeId) {
if ("A".equals(facadeId)) {
return new FacadeAException();
} else // ...
}
成员以传达不可用外观的 ID ,而不是抛出特定于外观的异常。或者,如果您不想将其放在FacadeException
本身上,则定义一个承载它的FacadeException
子类:
FacadeUnavailableException
有了它,您的问题就变得简单得多了:
public class FacadeUnavailableException extends FacadeException {
private final String facadeId;
private FacadeAException(String message, String facadeId) {
super(message);
this.facadeId = facadeId;
}
public String getFacadeId() {
return facadeId;
}
}