l

2013年12月25日 星期三

例外處理實務做法(2中)Exception Hierarchy、Tunneling Exception

Dec. 23 15:37~17:07

-2013-12-23-11.28.22_thumb2

圖片來源在此

 

在前一集介紹了Expressive Exception InterfaceThrowing ServerChecked Server ProblemHomogeneous ExceptionSmart Exception,今天繼續介紹《Java Idioms: Exception Handling》這篇文章中所提到的Exception Hierarchy與Tunneling Exception。

***

Exception Hierarchy

使用Homogeneous Exception的好處是客戶端程式可以用相同的方式來捕捉例外,在〈例外處理實務做法(2上)〉介紹Homogeneous Exception所提到的例子,無論是login()、withdraw()、deposit()發生例外,只要捕捉ATMOperationException即可。

login() throws ATMOperationException

withdraw() throws ATMOperationException

deposit() throws ATMOperationException

但是,Homogeneous Exception的優點也是它的缺點。萬一客戶端程式想要用不同的方式來處理login()、withdraw()、deposit()的例外該怎麼辦?

因此,建立例外類別繼承架構,讓更精確的例外類別繼承Homogeneous Exception。在介面宣告上函數會丟出Homogeneous Exception,在實作上則是丟出例外子類別。如此客戶端程式便可自由的選擇要捕捉Homogeneous Exception,或是其子類別。

 

螢幕快照 2013-12-23 下午3.59.51

 

Exception HierarchySmart Exception都是一種用來提供詳細錯誤資料的方法,前者透過繼承,後者則是透過包含一個錯誤資料列舉物件。Exception Hierarchy可以讓客戶端直接用不同的catch block來捕捉例外,省卻了Smart Exception只用一個catch block,但卻需要在catch block裡面用if條件式依據列舉物件的值來判斷錯誤原因的作法。

通常,如果錯誤原因不是很多,或是不同錯誤原因的處理方式各不相同,則可能會考慮採用Exception Hierarchy的方法。例如,Java的IOException就是一種Homogeneous Exception,而其子類別有:

ChangedCharSetException, CharacterCodingException, CharConversionException, ClosedChannelException, EOFException, FileLockInterruptionException, FileNotFoundException, FilerException, FileSystemException, HttpRetryException, IIOException, InterruptedByTimeoutException, InterruptedIOException, InvalidPropertiesFormatException, JMXProviderException, JMXServerErrorException, MalformedURLException, ObjectStreamException, ProtocolException, RemoteException, SaslException, SocketException, SSLException, SyncFailedException, UnknownHostException, UnknownServiceException, UnsupportedDataTypeException, UnsupportedEncodingException, UserPrincipalNotFoundException, UTFDataFormatException, ZipException

各自代表不同的錯誤狀況,處理的方式也都不相同,這時候套用Exception Hierarchy就比較合適。如果改用Smart Exception則每個catch (IOException e)的區塊都還要用if條件式來判斷詳細錯誤原因,很像傳統程序導向的寫法。

Java裡面有沒有Smart Exception?有,就是SQLException,她有一個public int getErrorCode()會傳回vendor-specific exception code(資料庫廠商所定義的錯誤代碼)。SQLException也是一個Homogeneous Exception,在處理資料庫的時候也會有很多種不同的錯誤原因,例如刪除的資料不存在、鍵值重複、表格不存在、資料表被鎖住、沒有操作權限等。造成這些錯誤的起因都可被歸類為「執行SQL指令所發生的錯誤」,只是產生錯誤的原因不同。再加上很多存取SQL資料庫的介面都是用error code來代表錯誤,因此用Smart Exception就比較合適。如果這裡要套用Exception Hierarchy,則有可能要產生數十到上百個例外物件,數量過多。

再補充說明,其實SQLException也有如下的子類別,和SQLException本身扮演Smart Exception所代表的錯誤狀況不同,以下這些例外,各用來表示與SQLException應採用不同處理方法的例外狀況,所以套用了Exception Hierarchy

BatchUpdateException, RowSetWarning, SerialException, SQLClientInfoException, SQLNonTransientException, SQLRecoverableException, SQLTransientException, SQLWarning, SyncFactoryException, SyncProviderException

***

Tunneling Exception

有時候一個函數不能宣告自己要丟出checked exception,例如你要實做別人定義的callback函數或是command pattern,如果原本的callback或是command沒有宣告會丟出任何checked exception,你的實作也就無法丟出任何的checked exception。

因此,定義一個繼承自RuntimeException的TunnelingException,丟出這個TunnelingException,並且把原本想要丟出的checked exception串接到TunnelingException身上。

TunnelingException是一種用在callback函數或是command pattern的例外宣告技巧,並非一定都是以RuntimeException子類別出現。例如,Java用來處理XML的ContentHandler介面,裡面有好幾個函數都宣告會丟出SAXException(一個checked exception),這個SAXException也是扮演TunnelingException的角色。也就是說,不管實作上可能會遭遇什麼例外,都要透過這個TunnelingException來傳遞。

還有沒有其他例子,有Java的AutoCloseable介面就只有一個函數:void close() throws Exception,這個Exception也是扮演著TunnelingException的角色。

***

還剩四個pattern,下集繼續。

***

友藏內心獨白:這兩個pattern都很實用。

沒有留言:

張貼留言