2015-06-09 14 views
5

Giả sử tôi có phương thức sẽ đăng một số nội dung trực tuyến và trả lại đúng/sai biểu thị thành công/thất bại.Mẫu chuẩn cho một phương pháp có thể thất bại vì các lý do khác nhau là gì?

Tuy nhiên, phương pháp của tôi có thể thất bại ở các bước khác nhau, ví dụ:

  • bị chặn bởi thư rác chặn lỗi
  • Mạng
  • ngoài dự kiến ​​ngoại lệ

tôi vẫn muốn phương pháp đơn giản trả lại một Boolean, tôi cũng không thích ý tưởng cho phép phương thức này chỉ ném ngoại lệ của nó và mọi người gọi phải bọc nó trong một try/catch (tôi ghét try/catch, nó luôn luôn xấu xí).

Có giải pháp chuẩn cho vấn đề này không?

Giải pháp tốt nhất mà tôi đưa ra là làm cho nó trở lại một enum thay vì với các kết quả có thể khác nhau, sau đó người gọi sẽ có một tuyên bố chuyển đổi. Có một giải pháp tốt hơn điều này?

CHỈNH SỬA: Tôi phải rõ ràng hơn; đây là một ứng dụng Android, người dùng sẽ đăng nhận xét trực tuyến, các lỗi khác nhau sẽ được dịch sang tin nhắn cho người dùng, ví dụ: "Spam, hãy đợi trước khi thử đăng lại"

+0

có, enum sẽ là tốt cho mục đích này. – ZhongYu

+1

'mỗi người gọi phải quấn nó trong một thử/catch' ngay cả khi bạn ném ngoại lệ, không cần phải quấn tất cả mọi thứ trong một thử/Bạn chỉ nên bắt ngoại lệ ở [các địa điểm thích hợp] (http://mikehadlow.blogspot.jp/2009/08/first-rule-of-exception-handling-do-not.html) –

+1

Bạn C# kẻ đã phá vỡ tôi lên. Java không cung cấp cho bạn một tùy chọn như vậy, bạn phải nắm bắt mọi ngoại lệ được kiểm tra (hoặc một trong các lớp cha mẹ của ngoại lệ). Đôi khi tôi ghen tị với bạn. Thông thường, tôi khóc cho bạn. Blog mà bạn vừa liên kết đến là cuồng loạn. –

Trả lời

3

Trả lại enum là tốt. Nhưng nếu bạn định gọi điều này từ nhiều nơi, bạn sẽ có cùng mã xử lý lỗi trong nhiều khu vực (ví dụ: cùng một tuyên bố switch).

Có lẽ một cách tiếp cận là trả về một boolean, nhưng đóng gói logic xử lý lỗi cụ thể bên trong trình xử lý lỗi. Vì vậy, bạn muốn xác định một giao diện như sau:

interface PostErrorHandler { 
    void handle(...); 
} 

Sau đó, bạn có thể có triển khai cụ thể:

public class SpamErrorHandler implements PostErrorHandler { 
    @Override 
    public void handle(...) { 
     ... //code to deal with spam 
    } 
} 

Chữ ký của phương pháp của bạn để gửi sau đó sẽ là:

public boolean post(String content, PostErrorHandler handler) { 
    ... 
} 

Bạn 'd rồi gọi handler.handle(...) dựa trên lỗi, từ trong vòng post.

Nếu bạn vẫn muốn truyền đạt loại lỗi xảy ra, bạn có thể sử dụng cách tiếp cận bạn đã đề cập: trả lại enum thay vì boolean.

Theo như ngoại lệ, nhiều hơn xấu, lý do chính mà sử dụng ngoại lệ ở đây là một ý tưởng tồi là có vẻ như các loại lỗi này được mong đợi. Nếu vậy, bạn đang mong đợi người gọi để đối phó với họ trong một số thời trang và họ dường như là một phần của logic kinh doanh của bạn. Nhưng việc sử dụng ngoại lệ không phải là cách chính xác cho các lỗi này. Bạn thường chỉ muốn sử dụng ngoại lệ nếu có điều gì đó không mong muốn xảy ra. Nếu bạn phải ném một ngoại lệ, thì tốt hơn là có một số loại phương pháp kiểm tra/kiểm tra trạng thái để kiểm tra đầu vào để cảnh báo bạn nếu đầu vào là xấu. Trong trường hợp đó bạn có thể ném một ngoại lệ (làm cho nó không được kiểm soát) bởi vì tình hình là bất ngờ, vì bạn mong đợi người gọi đã sử dụng phương pháp kiểm tra nhà nước trước khi gọi.

+0

Câu trả lời của bạn rất tuyệt, nhưng tôi nghĩ tôi nên rõ ràng hơn. Mã của tôi chỉ đơn giản là một ứng dụng Android, tôi sẽ dịch các lỗi khác nhau thành các thông báo cho người dùng, ví dụ: "Đã phát hiện spam, đợi trước khi đăng lại". –

+0

@Spacemonkey Nếu bạn kết thúc sao chép mã xử lý lỗi ở nhiều nơi, thì phương pháp xử lý có thể hoạt động tốt hơn. Nhưng nếu bạn chỉ làm điều này ở một nơi trung tâm, cách tiếp cận enum của bạn là hoàn toàn tốt đẹp. –

0

Một Enum có thể hoạt động, nhưng vì phương pháp của bạn sẽ "đăng một số nội dung trực tuyến", có thể xem xét sử dụng mã phản hồi HTTP làm hướng dẫn.

Mà không đi sâu vào chi tiết về multitude of HTTP response codes, biết rằng, đối với ví dụ của bạn:

  • bị chặn bởi chặn thư rác có thể là một 403 (Forbidden) hoặc một cái gì đó như thế lỗi
  • mạng có thể là một 503 (Dịch vụ không khả dụng) có lẽ là
  • Ngoại lệ không lường trước là khá nhiều ý nghĩa chính xác của lỗi 500.

Bạn có thể trả lại số nguyên từ phương thức của mình. Thành công sau đó sẽ được định nghĩa là mã trả về 100 nhỏ hơn 4.

Hy vọng điều này sẽ hữu ích.

+0

Phương pháp này có vẻ như là một phần của một số dịch vụ và bạn không muốn giới thiệu các mối quan tâm HTTP ở cấp độ này. Nhưng những gì bạn có thể làm là trả về các enums, và sau đó dịch các enums đó thành các mã phản hồi HTTP từ một lớp mà * có * đối phó với HTTP (từ một bộ điều khiển, chẳng hạn). –

+0

Có lẽ. Anh ta hỏi về kiểu trả về kiểu phương thức của anh ta sẽ "đăng một số nội dung trực tuyến" nên ... mà, với tôi, có vẻ như anh ta sẽ triển khai giao tiếp HTTP (có thể với một thư viện như Apache HTTP, hoặc có lẽ với ổ cắm thô). Nếu anh ta là, câu trả lời của tôi là ... tốt, đó là một lựa chọn. Nếu không, bạn có thể chính xác. Mặc dù vậy, anh ta không rõ 100%. –

+0

Tôi đồng ý - điều đó tùy thuộc vào cách anh ấy đang sử dụng phương pháp. Nhưng nói chung tôi muốn duy trì một tập hợp nhất quán ngữ nghĩa "nội bộ" khi làm việc với các dịch vụ của tôi. Nó chỉ ở những nơi tôi tương tác với một dịch vụ bên ngoài mà tôi thực hiện các bản dịch. –

0

Bạn sẽ vượt qua sự căm thù vô lý của bạn về thử/nắm bắt. Nó không phải là sự thật rằng tất cả người gọi phải quấn các cuộc gọi trong try/catch; nó có thể được thực hiện một cách thận trọng ở các cấp độ khác nhau trong mã, khi cần thiết; ví dụ: chỉ cấp cao nhất của ứng dụng của bạn cần phải lo lắng về việc bắt các ngoại lệ "hết bộ nhớ" hoặc "toàn bộ đĩa". Trong khi đó, cấu trúc try/catch có thể được sử dụng với các từ khóa khác (chẳng hạn như finally), bạn sẽ có quyền truy cập vào các ngoại lệ lồng nhau và dấu vết ngăn xếp và tổng thể sẽ có trải nghiệm gỡ lỗi phong phú hơn nhiều.

Mặt khác, nếu bạn chỉ muốn một Boolean, có một mẫu đặt tên được sử dụng trong CLR rất phổ biến. Bạn sẽ cung cấp hai chức năng thực chất giống như vậy.

try 
{ 
    string output = MakeSomeFunctionCall(input); 
} 
catch 
{ 
} 

... đôi khi được bổ sung chức năng của đối tác thực hiện tương tự nhưng trả về Boolean, ví dụ:

string output; 
bool success = TryMakeSomeFunctionCall(input, out output); 

này mang lại cho người gọi một sự lựa chọn của việc sử dụng try/catch (nếu thông tin lỗi chi tiết là cần thiết) hoặc bằng cách sử dụng "Thử *" phương pháp (nếu thông tin lỗi chi tiết không cần thiết).

Sử dụng mẫu này và phải rõ ràng cho người khác những gì đang diễn ra trong mã của bạn.

0

tôi khá-thẳng thắn là có ý kiến ​​rằng "có một [rất tốt] lý do lý do tại sao chúng tôi bắt đầu 'ném ngoại lệ' thay vì 'sử dụng trở lại-mã.'"

Vấn đề quan trọng với " cách tiếp cận "mã trả lại" là mỗi ứng dụng khách phải, với mỗi cuộc gọi, xử lý và xử lý đúng mọi mã trả lại.

... Và hơn nữa, nó có nghĩa vụ phải làm tất cả những điều này, ngay cả khi ("gần như luôn luôn như vậy ...") không có gì sai.

Khi thư viện thay vào đó, "ném ngoại lệ", ứng dụng khách không phải kiểm tra để xem liệu yêu cầu có thành công hay không. ("Nếu chúng ta vẫn còn sống, thì nó đã thành công.") Các khách hàng có thể bây giờ catch các cụ trường hợp ngoại lệ mà nó có thể dự đoán, trong khi cho phép bất kỳ trường hợp ngoại lệ bỏ bắt để 'bong bóng lên' với một bộ xử lý ngoài cấp.

tôi thân ái đề nghị rằng có khôn ngoan trong chiến lược đó ...

+0

Cảm ơn câu trả lời của bạn, điều đó rất có ý nghĩa đối với tôi. –

+0

Tuyệt vời. "'Ngoại lệ' là .. sau tất cả .. * 'ngoại lệ!' *" :-D –

Các vấn đề liên quan