2008-08-25 30 views
11

Tôi biết hai phương pháp xử lý Ngoại lệ, cho phép xem xét chúng.Xử lý ngoại lệ: Hợp đồng và Cách tiếp cận đặc biệt

  1. Cách tiếp cận hợp đồng.

    Khi một phương pháp không thực hiện những gì nó nói nó sẽ làm trong tiêu đề phương thức, nó sẽ ném một ngoại lệ. Vì vậy, phương pháp "hứa ​​hẹn" rằng nó sẽ làm các hoạt động, và nếu nó không vì một lý do nào đó, nó sẽ ném một ngoại lệ.

  2. Cách tiếp cận vượt trội.

    Chỉ ném ngoại lệ khi có điều gì đó thực sự kỳ lạ xảy ra. Bạn không nên sử dụng ngoại lệ khi bạn có thể giải quyết tình huống bằng luồng điều khiển thông thường (Nếu phát biểu). Bạn không sử dụng Ngoại lệ cho luồng kiểm soát, như bạn có thể trong cách tiếp cận hợp đồng.

Cho phép sử dụng cả hai phương pháp trong các trường hợp khác nhau:

Chúng tôi có một lớp khách hàng mà có một phương pháp gọi là OrderProduct.

cách tiếp cận hợp đồng:

class Customer 
{ 
    public void OrderProduct(Product product) 
    { 
      if((m_credit - product.Price) < 0) 
        throw new NoCreditException("Not enough credit!"); 
      // do stuff 
    } 
} 

phương pháp đặc biệt:

class Customer 
{ 
    public bool OrderProduct(Product product) 
    { 
      if((m_credit - product.Price) < 0) 
        return false; 
      // do stuff 
      return true; 
    } 
} 

if !(customer.OrderProduct(product)) 
      Console.WriteLine("Not enough credit!"); 
else 
    // go on with your life 

Ở đây tôi thích cách tiếp cận đặc biệt, vì nó không phải là thực sự vượt trội mà khách hàng không có tiền giả định ông không giành chiến thắng trong xổ số .

Nhưng đây là một tình huống mà tôi nhầm lẫn về kiểu hợp đồng.

vượt trội:

class CarController 
{ 
    // returns null if car creation failed. 
    public Car CreateCar(string model) 
    { 
     // something went wrong, wrong model 
     return null; 
    } 
} 

Khi tôi gọi một phương thức gọi là CreateCar, tôi chết tiệt wel mong đợi một trường hợp xe thay vì một số con trỏ null tệ hại, mà có thể tàn phá đang chạy của tôi một chục dòng sau. Do đó, tôi thích hợp đồng với điều này:

class CarController 
{ 

    public Car CreateCar(string model) 
    { 
     // something went wrong, wrong model 
     throw new CarModelNotKnownException("Model unkown"); 

     return new Car(); 
    } 
} 

Bạn sử dụng kiểu nào? Bạn nghĩ gì là cách tiếp cận chung nhất cho Ngoại lệ?

Trả lời

7

Tôi ưu tiên những gì bạn gọi là cách tiếp cận "hợp đồng". Trả về giá trị rỗng hoặc các giá trị đặc biệt khác để cho biết lỗi không cần thiết trong ngôn ngữ hỗ trợ ngoại lệ. Tôi tìm thấy nó dễ dàng hơn để hiểu mã khi nó không có một loạt các mệnh đề "if (result == NULL)" hoặc "if (result == -1)" được trộn lẫn với những gì có thể rất đơn giản, logic đơn giản.

+0

+1 cho ví dụ về trả lại kết quả bằng 0 hoặc 0. Thay vì làm cho mã rõ ràng hơn, hàm trả về null hoặc -1 buộc người viết của phương thức gọi để biết cách phương thức được gọi chọn báo cáo một kết quả không chuẩn. Trường hợp ngoại lệ là một cách tiếp cận hợp pháp, rõ ràng hơn, trong đó người gọi có thể coi điều khoản được gọi là hộp đen thay đổi (có thể). Tất cả những người được mời phải biết rằng nó sẽ phải xử lý một ngoại lệ, không phải hôm nay là ngày hôm nay và ngày hôm sau là Integer.MIN_VALUE. – rajah9

0

Tôi tin rằng nếu bạn đang xây dựng một lớp học sẽ được chương trình bên ngoài sử dụng (hoặc sẽ được sử dụng lại bởi các chương trình khác) thì bạn nên sử dụng cách tiếp cận hợp đồng. Một ví dụ điển hình về điều này là một API thuộc bất kỳ loại nào.

1

Cách tiếp cận thông thường của tôi là sử dụng hợp đồng để xử lý bất kỳ loại lỗi nào do lệnh "khách hàng", nghĩa là do lỗi bên ngoài (tức là ArgumentNullException).

Mọi lỗi trên đối số không được xử lý. Một ngoại lệ được nâng lên và "client" chịu trách nhiệm xử lý nó. Mặt khác, đối với các lỗi nội bộ, luôn luôn cố gắng sửa chúng (như thể bạn không thể nhận được kết nối cơ sở dữ liệu vì một lý do nào đó) và chỉ khi bạn không thể xử lý nó, hãy loại bỏ ngoại lệ. Điều quan trọng cần lưu ý là hầu hết các ngoại lệ chưa được giải quyết ở cấp độ như vậy sẽ không thể được xử lý bởi khách hàng, do đó, họ sẽ chỉ có thể đi đến xử lý ngoại lệ chung nhất, do đó, nếu như một ngoại lệ xảy ra, bạn đang ở đây. có lẽ FUBAR.

0

Cả hai cách tiếp cận đều đúng. Điều đó có nghĩa là một hợp đồng nên được viết theo cách như vậy để chỉ định cho tất cả các trường hợp không thực sự ngoại lệ một hành vi mà không yêu cầu ném một ngoại lệ.

Lưu ý rằng một số trường hợp có thể hoặc có thể không ngoại lệ dựa trên những gì người gọi của mã đang mong đợi. Nếu người gọi đang mong rằng một từ điển sẽ chứa một mục nào đó, và sự vắng mặt của mục đó sẽ chỉ ra một vấn đề nghiêm trọng, thì không tìm được vật phẩm là một điều kiện đặc biệt và sẽ gây ra một ngoại lệ. Tuy nhiên, nếu người gọi thực sự không biết liệu một mục có tồn tại hay không, và chuẩn bị sẵn sàng để xử lý sự hiện diện của nó hoặc sự vắng mặt của nó, thì sự vắng mặt của vật phẩm sẽ là điều kiện mong đợi và không gây ra ngoại lệ. Cách tốt nhất để xử lý các biến thể như vậy trong kỳ vọng người gọi là có một hợp đồng chỉ định hai phương thức: phương thức DoSomething và phương thức TryDoSomething, ví dụ:

 
TValue GetValue(TKey Key); 
bool TryGetValue(TKey Key, ref TValue value); 

Lưu ý rằng, trong khi mô hình 'thử' tiêu chuẩn được như minh họa trên, một số lựa chọn thay thế cũng có thể hữu ích nếu ai thiết kế một giao diện trong đó sản xuất các mặt hàng:

 
// In case of failure, set ok false and return default<TValue>. 
TValue TryGetResult(ref bool ok, TParam param); 
// In case of failure, indicate particular problem in GetKeyErrorInfo 
// and return default<TValue>. 
TValue TryGetResult(ref GetKeyErrorInfo errorInfo, ref TParam param); 

Lưu ý rằng việc sử dụng một cái gì đó như mẫu TryGetResult bình thường trong một giao diện sẽ làm cho giao diện bất biến đối với kiểu kết quả; bằng cách sử dụng một trong các mẫu ở trên sẽ cho phép giao diện được so khớp đối với loại kết quả. Ngoài ra, nó sẽ cho phép kết quả được sử dụng trong khai báo 'var':

 
    var myThingResult = myThing.TryGetSomeValue(ref ok, whatever); 
    if (ok) { do_whatever } 

Không hoàn toàn là cách tiếp cận tiêu chuẩn, nhưng trong một số trường hợp, lợi thế có thể biện minh cho nó.