2010-06-08 77 views
2

我有一些業務邏輯可以捕捉一些邏輯上無效的情況,例如試圖扭轉已經扭轉的交易。在這種情況下,正確的操作是通知用戶:如何區分我可以向用戶展示的例外,以及我無法展示的例外?

交易已經逆轉

不能扭轉倒車交易

您沒有權限扭轉交易

這項交易是對已經關閉

該交易是一個會話太舊,無法逆轉

問題是,我如何將這些特殊情況通知給調用代碼,以便他們可以顯示用戶?

做我創建的每個情況下,單獨的例外:

catch (ETransactionAlreadyReversedException) 
    MessageBox.Show('Transaction already reversed') 
catch (EReversingAReversingTransactionException) 
    MessageBox.Show('Cannot reverse a reversing transaction') 
catch (ENoPermissionToReverseTranasctionException) 
    MessageBox.Show('You do not have permission to reverse transactions') 
catch (ECannotReverseTransactionOnAlredyClosedSessionException) 
    MessageBox.Show('This transaction is on a session that has already been closed') 
catch (ECannotReverseTooOldTransactionException) 
    MessageBox.Show('This transaction is too old to be reversed') 

下行的是,當有一個新的邏輯的情況下向用戶顯示:由NSL創建

Tranasctions不能顛倒

我不是簡單地向用戶顯示一條消息,而是將其作爲一個未處理的消息泄漏出去,當它真的應該被處理時另一個MessageBox

另一種方法是創建一個單一異常類:

`EReverseTransactionException` 

隨着理解,這種類型的任何異常是一個邏輯檢查,應與一個消息框進行處理:

catch (EReverseTransactionException) 

但是仍然認識到,任何其他例外,例如涉及內存ECC奇偶校驗錯誤的例外,都會繼續未處理。

換句話說,我不轉換所有的錯誤,可以通過ReverseTransaction()方法被扔進EReverseTransactionException,只有那些在邏輯上是用戶的無效的原因。

回答

3

我發現有各種大類的異常:

  1. TransientException - 你剛纔試了一下沒有工作,但如果你再試一次它可能。用於數據庫目前不可用的情況。
  2. InvalidRequestException - 你只是要求一些不能完成的事情(你的例子適合在這裏)
  3. SystemException - 系統生病了,我們已經忘記了你剛纔說的一切,你的會話已經死了,你需要開始再一次。

我會有這三種主要類型的異常,並抓住他們每個人,每種情況下都有明顯的具體行動。我所有的例外都來自這三種類型。

+1

+1因爲我真的很喜歡你對每種情況的簡單描述,特別是*「系統生病了」* Aaronaught似乎同意你的看法,使用'ClientException'和'BusinessRuleException'。 **編輯:**在每種情況下,您的三個基本例外的名稱是什麼? – 2010-06-08 14:32:45

1

我推薦帶有原因標識符的單例外。原因本身可能是一個異常,它包裹在你的用戶異常中,儘管我認爲這主要是爲了調試目的,或者作爲獲取更多細節的手段。

您的主要異常包括一個標識符,它能簡潔地識別用戶做錯了什麼。它可以用作檢索本地化消息以顯示用戶的基礎,用於鏈接到用戶文檔,幫助,故障排除和其他幫助。

消息ID作爲錯誤代碼也很有用,它可用於報告問題並記錄支持團隊支持文檔中的解決方案。

我對所有用戶級別的異常使用超類,允許使用ID來標識情況或原因。所有的ID都被記錄下來,並且每個都至少有一個測試用例來引發異常。

3

對我來說,經驗法則是讓用戶看到確切的錯誤信息是否有用。這在不同類型的應用程序之間變化很大。數以百萬計的「普通用戶」使用的桌面應用程序與由100多名訓練有素的專業人員使用的企業Web應用程序完全不同。

對於前者,最好是顯示一個通用的「系統錯誤,請重新啓動」類型的消息,而不是用戶不理解的技術細節,並且通常不打算轉發給支持部門(除非它可以通過按下按鈕來完成)。

我們的項目是後一種情況,而用戶通常向前問題支持。因此,我們嘗試改進錯誤消息以包含與支持團隊相關的信息。由於我們是一個傳統的應用程序,我們不太擔心內存奇偶校驗錯誤,而不是普通空指針異常和代碼中的邏輯錯誤。

對於不同的異常類型的號碼,我喜歡簡單的粉絲,所以我嘗試用異常類型,每一個不同的類錯誤的最小必要數量度日。什麼構成一個單獨的類別還由錯誤發生的時間和方式以及如何處理和何時處理來定義。由於您的案例首先與相同的用例相關聯,因此我將使用具有特定明細消息的單一異常類型。

+0

我使用了內存ecc奇偶校驗錯誤來避免可能發生的關於如何處理非業務規則錯誤的神聖戰爭(例如,如果存在主鍵衝突或TCP/IP連接失敗 - 我的代碼技術上可以嘗試的事情處理;但我寧願不)所以通過選擇一個錯誤,大家一致認爲我可以做*沒有*關於,我得到削減追逐和專注於沒有解決方案,除了「再試一次」的錯誤 – 2010-06-08 14:30:12

+0

@伊恩,我看到你的觀點 - 這個例子起初對我來說聽起來有點奇怪:-) – 2010-06-08 14:33:42

1

你從基礎Exception派生所有異常的(或EException或任何等價物是在你的語言?)

我處理這從一個ClientException(用戶提供無效輸入導出所有的業務邏輯錯誤)或BusinessRuleException(輸入有效,但會在不知不覺中違反一些重要的業務或域規則)。

任何來自這些根源的異常都可以捕獲並顯示給用戶。除非代碼知道如何處理它們,否則其他異常會轉到全局異常處理程序。

(其實,這是不完全準確。真正的情況是,全球異常處理程序本身可以識別這些異常和不同的方式處理它們,但原理是一樣的。)

+0

現在我在這個被標記的答案或djna之間撕裂了。 – 2010-06-28 23:13:31

+0

@Ian:由於這裏沒有客觀/技術上正確的答案,所以您應該接受哪一個最能解決*您的*特殊問題。我們的答案是互補的;我主要關注*預期*異常的層次結構,而他是對所有可能異常的更廣泛的分類。無論哪一個幫助你更多。 – Aaronaught 2010-06-29 00:41:07

+0

那麼我回到了stackoverflow,找到我記得的答案,這給了兩個例外的具體例子,以及它們被拋出時的邏輯。原來這是這個答案,而不是我之前接受的答案。另一方面,接受的答案是你的超級集合,但缺乏具體的例子。他們應該是共同的答案。 – 2010-06-29 13:58:31

1

你應該創建單獨的異常時,您需要(或期望需要)不同類型的行爲來處理不同的例外。如果你只是想不同消息顯示,但基本的行爲將是所有的人都一樣,那麼你可能只是想從std::runtime_error獲得一個異常類:

class transaction_error : public std::runtime_error { 
public: 
    transaction_error(std::string const &caption) : std::runtime_error(caption) {} 
}; 

,你會扔是這樣的:

throw transaction_error("Transaction already reversed"); 

...,趕上這樣的:

try { 
    execute_transaction(transaction_data); 
} 
catch(transaction_error const &e) { 
    MessageBox(NULL, e->what(), "Transaction Error", MB_OK); 
} 
相關問題