3 回答

TA貢獻1780條經驗 獲得超5個贊
您可以使用泛型,但這還不夠,因為您需要在運行時實例化特定類型。
從廣義上講,您有兩種方法:
反思方式
聲明方式
1)反射方式不簡單。Java 并沒有提供所有你需要做的事情。您可以啟發或使用庫作為 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()或 better來實例化泛型的類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參數,但總的想法是一樣的。

TA貢獻1780條經驗 獲得超1個贊
停在 有兩個很好的理由throws FacadeException
:
FacadeBase.checkFacade
無論如何,合同都會迫使客戶捕捉FacadeException
(假設編程接口的良好做法)異常類不能是通用的。盡管您可以
Exception
在throws
子句中使用類型參數,但這只是過度設計(除了違背最佳實踐)
所以子類應該throws Facade<A...Z>Exception
在適用的地方完全聲明或省略這個子句。但這對客戶端/調用者沒有影響(除非他們采取不鼓勵的聲明子類類型的方式)
如果您需要檢查調用方引發了哪個異常,那么無論如何您都必須知道具體的異常類,因為instanceof T
無論如何您都無法檢查。

TA貢獻1821條經驗 獲得超6個贊
據我了解,問題的核心是如何按照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);
}
}
...
}
我首先注意到,將特征異常與具體FacadeBase子類相關聯會破壞抽象。子類當然可能會拋出它們自己的特定異常,但是一旦其他類知道或特別關心那些異常,特別是為了能夠識別這些子類,抽象就會崩潰。
特別是,如果您的isFacadeAvailable(facadeId)方法與FacadeBase在 Java 類路徑中可用的子類有關,那么這似乎與該外觀實現的特征異??捎糜嘘P。在這種情況下,您不能期望能夠實例化FacadeQExceptionwhenFacadeQ不可用,并且當類路徑中不存在任何異常時,您可能會遇到類加載失敗。
其次,我觀察到因為所有的Facade[A-Z]Exceptions 都擴展了FacadeException,FacadeBase.checkFacade()所以可以簡單地聲明FacadeException而不是聲明所有單獨的異常。這不會阻止其他代碼捕獲特定異常,如果這些異常確實仍然被此方法拋出。
為了實際拋出個別例外,您需要先建立他們,并呼吁無論是大的switch塊,大if/ then/else語句,一個工廠方法,或適當的異常類的反射實例,或這些的某種組合. 請注意,異常是對象;它們可以分配給變量并從方法中返回。一個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 // ...
}
但是,我敦促您考慮提供FacadeException一個成員來傳達不可用外觀的ID,而不是通過拋出特定于外觀的異常來實現。或者如果你不想把它放在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;
}
}
有了這個,你的問題就變得簡單多了:
public void checkFacade(final String facadeId) throws FacadeUnavailableException {
if (!isFacadeAvailable(facadeId)) {
throw new FacadeUnavailableException("unavailable", facadeId);
}
}
添加回答
舉報