Là suy nghĩ lại một ngoại lệ rò rỉ một trừu tượng?


12

Tôi có một phương thức giao diện ghi rõ trong tài liệu, nó sẽ đưa ra một loại ngoại lệ cụ thể. Việc thực hiện phương pháp đó sử dụng một cái gì đó ném một ngoại lệ. Ngoại lệ nội bộ được bắt và ngoại lệ được khai báo bởi hợp đồng giao diện được đưa ra. Đây là một ví dụ mã nhỏ để giải thích rõ hơn. Nó được viết bằng PHP nhưng khá đơn giản để làm theo.

// in the interface

/**
 * @return This method returns a doohickey to use when you need to foo
 * @throws DoohickeyDisasterException
 */
public function getThatDoohickey();

// in the implementation

public function getThatDoohickey() {

    try {
        $SomethingInTheClass->doSomethingThatThrowsAnException();
    } catch (Exception $Exc) {
        throw new DoohickeyDisasterException('Message about doohickey failure');
    }

    // other code may return the doohickey

}

Tôi đang sử dụng phương pháp này trong một nỗ lực để ngăn chặn sự trừu tượng bị rò rỉ.

Câu hỏi của tôi là: Liệu việc vượt qua ngoại lệ bị ném như ngoại lệ trước đó có bị rò rỉ sự trừu tượng không? Nếu không, nó có phù hợp để sử dụng lại thông điệp của ngoại lệ trước đó không? Nếu nó bị rò rỉ thì sự trừu tượng, bạn có thể cung cấp một số hướng dẫn về lý do tại sao bạn nghĩ nó không?

Chỉ cần làm rõ, câu hỏi của tôi sẽ liên quan đến việc thay đổi dòng mã sau đây

throw new DoohickeyDisasterException($Exc->getMessage(), null, $Exc);

Trường hợp ngoại lệ nên về nguyên nhân không phải về người ném chúng . Nếu mã của bạn có thể có a file_not_found, thì nó nên ném a file_not_found_exception. Ngoại lệ không nên là thư viện cụ thể.
Vịt Mooing

Câu trả lời:


11

Câu hỏi của tôi là: Liệu việc vượt qua ngoại lệ bị ném như ngoại lệ trước đó có bị rò rỉ sự trừu tượng không? Nếu không, nó có phù hợp để sử dụng lại thông điệp của ngoại lệ trước đó không?

Câu trả lơi con phụ thuộc vao nhiêu thư".

Cụ thể, nó phụ thuộc vào ngoại lệ, và ý nghĩa của nó. Về bản chất, việc xem xét lại có nghĩa là bạn đang thêm nó vào giao diện của mình. Bạn sẽ làm điều đó nếu bạn đã viết mã mà bạn đang gọi cho mình, hay đây chỉ là để tránh thương hiệu ngoại lệ?

Nếu ngoại lệ của bạn bao gồm một dấu vết đến nguyên nhân gốc, trong mã được gọi, có thể rò rỉ dữ liệu bên ngoài sự trừu tượng - nhưng, nói chung, tôi nghĩ rằng có thể chấp nhận được vì ngoại lệ được xử lý bởi người gọi (và không ai quan tâm đến nó ở đâu đến từ) hoặc hiển thị cho người dùng (và bạn muốn biết nguyên nhân gốc để gỡ lỗi.)

Tuy nhiên, thường xuyên, chỉ cho phép ngoại lệ thông qua là một lựa chọn thực hiện rất hợp lý và không phải là vấn đề trừu tượng. Chỉ cần hỏi "tôi có ném cái này không nếu mã tôi đang gọi không?"


8

Nói một cách chính xác, nếu ngoại lệ 'bên trong' tiết lộ bất cứ điều gì về hoạt động bên trong của một triển khai, thì bạn đang bị rò rỉ. Vì vậy, về mặt kỹ thuật, bạn nên luôn luôn nắm bắt mọi thứ và ném loại ngoại lệ của riêng bạn.

NHƯNG.

Khá nhiều tranh luận quan trọng có thể được đưa ra để chống lại điều này. Đáng chú ý nhất:

  • Ngoại lệ là những điều đặc biệt ; họ đã vi phạm các quy tắc 'hoạt động bình thường' theo nhiều cách, vì vậy họ cũng có thể vi phạm đóng gói và trừu tượng ở cấp độ giao diện.
  • Lợi ích của việc có dấu vết ngăn xếp có ý nghĩathông tin lỗi tại điểm thường vượt xa tính chính xác của OOP, miễn là bạn không rò rỉ thông tin chương trình nội bộ qua hàng rào UI (sẽ được tiết lộ thông tin).
  • Việc bao bọc mọi ngoại lệ bên trong trong một loại ngoại lệ phù hợp bên ngoài có thể dẫn đến rất nhiều mã soạn sẵn vô dụng , đánh bại toàn bộ mục đích của các ngoại lệ (cụ thể là thực hiện xử lý lỗi mà không gây ô nhiễm dòng mã thông thường với xử lý lỗi nồi hơi).

Điều đó nói rằng, bắt và gói ngoại lệ thường ý nghĩa, nếu chỉ để thêm thông tin bổ sung vào nhật ký của bạn hoặc để tránh rò rỉ thông tin nội bộ cho người dùng cuối. Xử lý lỗi vẫn là một hình thức nghệ thuật và thật khó để đưa nó xuống một vài quy tắc chung. Một số trường hợp ngoại lệ nên được đưa ra, một số khác không nên và quyết định cũng phụ thuộc vào bối cảnh. Nếu bạn đang mã hóa giao diện người dùng, bạn không muốn để bất kỳ điều gì cho người dùng không được lọc; nhưng nếu bạn đang mã hóa một thư viện thực hiện một số giao thức mạng, việc tạo ra một số ngoại lệ nhất định có lẽ là điều nên làm (sau tất cả, nếu mạng bị hỏng, bạn có thể làm rất ít để tăng cường thông tin hoặc khôi phục và tiếp tục ; dịch NetworkDownExceptionsang FoobarNetworkDownExceptionchỉ là vô nghĩa).


6

Trước hết, những gì bạn đang làm ở đây không phải là một ngoại lệ. Suy nghĩ lại sẽ là ném ngoại lệ theo nghĩa đen, như thế này:

try {
    $SomethingInTheClass->doSomethingThatThrowsAnException();
} catch (Exception $Exc) {
    throw $Exc;
}

Rõ ràng, điều này là một chút vô nghĩa. Việc chia sẻ lại là dành cho các trường hợp bạn muốn giải phóng một số tài nguyên hoặc ghi nhật ký ngoại lệ hoặc bất cứ điều gì khác mà bạn có thể muốn làm, mà không ngăn chặn ngoại lệ xuất hiện trong ngăn xếp.

Những gì bạn đang làm là thay thế tất cả các ngoại lệ, bất kể nguyên nhân là gì, với DoohickeyDisasterException. Mà có thể hoặc không thể là những gì bạn định làm. Nhưng tôi sẽ đề nghị rằng bất cứ khi nào bạn làm điều này, bạn cũng nên làm như bạn đề xuất và vượt qua ngoại lệ ban đầu như một ngoại lệ bên trong, chỉ trong trường hợp nó hữu ích trong theo dõi ngăn xếp.

Nhưng đây không phải là về trừu tượng rò rỉ, đó là một vấn đề khác.

Để trả lời câu hỏi liệu một ngoại lệ bị rút lại (hoặc thực sự là một ngoại lệ chưa được phát hiện) có thể là một sự trừu tượng bị rò rỉ hay không, tôi sẽ nói rằng nó phụ thuộc vào mã gọi của bạn. Nếu mã đó đòi hỏi kiến ​​thức về khung trừu tượng thì đó là một sự trừu tượng bị rò rỉ, bởi vì nếu bạn thay thế khung đó bằng một khung khác thì bạn phải thay đổi mã bên ngoài sự trừu tượng hóa của bạn.

Ví dụ: nếu DoohickeyDisasterException là một lớp trong khung và mã gọi của bạn trông như thế này, thì bạn có một bản tóm tắt bị rò rỉ:

try {
    $wrapper->getThatDoohickey();
} catch (DoohickeyDisasterException $Exc) {
    echo "The Doohickey is all wrong!";
    echo $Exc->getMessage();
    gotoAHappyPlaceAndSingHappySongs();
}

Nếu bạn thay thế khung bên thứ ba của mình bằng khung khác, sử dụng tên ngoại lệ khác và bạn phải tìm tất cả các tham chiếu này và thay đổi chúng. Tốt hơn là tạo lớp Exception của riêng bạn và bọc ngoại lệ khung trong đó.

Mặt khác, nếu DoohickeyDisasterException là một trong những sản phẩm của riêng bạn thì bạn không bị rò rỉ trừu tượng, bạn nên quan tâm đến bản thân nhiều hơn với quan điểm đầu tiên của tôi.


2

Quy tắc tôi cố gắng thực hiện là: bọc nó nếu bạn gây ra nó. Tương tự, nếu một lỗi được tạo ra do ngoại lệ thời gian chạy, thì đó phải là một loại DoHickeyException hoặc MyApplicationException.

Điều đó ngụ ý là nếu nguyên nhân gây ra lỗi là do bên ngoài mã của bạn và bạn không hy vọng nó sẽ thất bại thì hãy thất bại một cách duyên dáng và suy nghĩ lại. Tương tự, nếu đó là một vấn đề với mã của bạn, thì hãy bọc nó trong một ngoại lệ tùy chỉnh (có khả năng).

Ví dụ: nếu một tệp dự kiến ​​sẽ nằm trên đĩa hoặc dự kiến ​​sẽ có một dịch vụ , thì hãy xử lý nó một cách duyên dáng và ném lại lỗi để người tiêu dùng mã của bạn có thể tìm ra lý do tại sao tài nguyên đó không khả dụng. Nếu bạn đã tạo quá nhiều dữ liệu cho một số loại, thì đó là lỗi của bạn để bọc và ném.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.