Cảnh báo! Lập trình viên C ++ đến đây với những ý tưởng có thể khác nhau về cách xử lý ngoại lệ nên được thực hiện khi cố gắng trả lời một câu hỏi chắc chắn về ngôn ngữ khác!
Đưa ra ý tưởng này:
Ví dụ: hãy tưởng tượng chúng ta có tài nguyên tìm nạp, thực hiện yêu cầu HTTP và trả về dữ liệu đã truy xuất. Và thay vì các lỗi như ServiceT tạmUnav Available hoặc RateLimitExceeded, chúng tôi sẽ chỉ đưa ra một RetryableError đề xuất cho người tiêu dùng rằng họ chỉ nên thử lại yêu cầu và không quan tâm đến thất bại cụ thể.
... Một điều tôi muốn đề xuất là bạn có thể trộn lẫn các mối lo ngại về việc báo cáo lỗi với các khóa hành động để phản hồi theo cách có thể làm giảm tính tổng quát của mã của bạn hoặc yêu cầu nhiều "điểm dịch" cho các ngoại lệ .
Ví dụ: nếu tôi mô hình hóa một giao dịch liên quan đến việc tải một tệp, nó có thể thất bại vì một số lý do. Có lẽ tải tệp liên quan đến việc tải một plugin không tồn tại trên máy của người dùng. Có lẽ tập tin chỉ đơn giản là bị hỏng và chúng tôi đã gặp lỗi khi phân tích cú pháp.
Bất kể điều gì xảy ra, hãy nói rằng quá trình hành động là báo cáo những gì đã xảy ra với người dùng và nhắc anh ta về những gì anh ta muốn làm về nó ("thử lại, tải một tệp khác, hủy bỏ").
Thrower vs Catch
Quá trình hành động đó được áp dụng bất kể loại lỗi nào chúng tôi gặp phải trong trường hợp này. Nó không được nhúng vào ý tưởng chung về lỗi phân tích cú pháp, nó không được nhúng vào ý tưởng chung về việc không tải được plugin. Nó được nhúng vào ý tưởng gặp phải các lỗi như vậy trong bối cảnh chính xác của việc tải tệp (kết hợp tải tệp và không thành công). Vì vậy, thông thường tôi thấy nó, nói một cách thô thiển, là catcher's
trách nhiệm xác định tiến trình hành động để đáp ứng với một ngoại lệ bị ném (ví dụ: nhắc nhở người dùng với các tùy chọn), chứ không phải thrower's
.
Nói cách khác, các trang web throw
ngoại lệ thường thiếu loại thông tin theo ngữ cảnh này, đặc biệt là nếu các chức năng ném thường được áp dụng. Ngay cả trong bối cảnh hoàn toàn thoái hóa khi họ có thông tin này, bạn vẫn tự mình dồn vào chân tường về hành vi phục hồi bằng cách nhúng nó vào throw
trang web. Các trang web catch
thường là nơi có nhiều thông tin nhất có sẵn để xác định tiến trình hành động và cung cấp cho bạn một vị trí trung tâm để sửa đổi nếu quá trình hành động đó sẽ thay đổi đối với giao dịch đã cho đó.
Khi bạn bắt đầu cố gắng đưa ra các ngoại lệ không còn báo cáo những gì sai nhưng cố gắng xác định những việc cần làm, điều đó có thể làm giảm tính tổng quát và tính linh hoạt của mã của bạn. Một lỗi phân tích không phải lúc nào cũng dẫn đến loại dấu nhắc này, nó thay đổi theo bối cảnh trong đó một ngoại lệ như vậy được ném (giao dịch mà nó được ném).
Người ném mù
Nói chung, rất nhiều thiết kế xử lý ngoại lệ thường xoay quanh ý tưởng về một người ném mù. Nó không biết làm thế nào ngoại lệ sẽ bị bắt, hoặc ở đâu. Điều tương tự cũng áp dụng cho các hình thức khôi phục lỗi cũ hơn bằng cách sử dụng lan truyền lỗi thủ công. Các trang web gặp lỗi không bao gồm quá trình hành động của người dùng, họ chỉ nhúng thông tin tối thiểu để báo cáo loại lỗi nào đã gặp phải.
Đảo ngược trách nhiệm và khái quát hóa người bắt
Khi suy nghĩ về điều này cẩn thận hơn, tôi đã cố gắng tưởng tượng ra loại cơ sở mã hóa nơi điều này có thể trở thành cám dỗ. Trí tưởng tượng của tôi (có thể sai) là nhóm của bạn vẫn đang đóng vai trò là "người tiêu dùng" ở đây và thực hiện hầu hết các mã gọi điện. Có lẽ bạn có rất nhiều giao dịch khác nhau (rất nhiều try
khối) tất cả có thể gặp phải cùng một bộ lỗi và tất cả, từ quan điểm thiết kế, dẫn đến một quá trình phục hồi thống nhất.
Cân nhắc lời khuyên khôn ngoan từ Lightness Races in Orbit's
câu trả lời tốt (mà tôi nghĩ là thực sự đến từ một tư duy định hướng thư viện tiên tiến), bạn vẫn có thể bị ném ra ngoại lệ "phải làm gì", chỉ gần hơn với trang web khôi phục giao dịch.
Có thể tìm thấy một trang web xử lý giao dịch phổ biến, trung gian trong số này ở đây thực sự tập trung vào các mối quan tâm "phải làm gì" nhưng vẫn trong bối cảnh bị bắt.
Điều này sẽ chỉ áp dụng nếu bạn có thể thiết kế một số loại chức năng chung mà tất cả các giao dịch bên ngoài này sử dụng (ví dụ: một chức năng nhập một chức năng khác để gọi hoặc một lớp cơ sở giao dịch trừu tượng với mô hình hành vi có thể ghi đè lên trang web giao dịch trung gian này có khả năng nắm bắt tinh vi ).
Tuy nhiên, người ta có thể chịu trách nhiệm tập trung vào quá trình hành động của người dùng để đối phó với nhiều lỗi có thể xảy ra, và vẫn trong bối cảnh bắt hơn là ném. Ví dụ đơn giản (mã giả Python-ish và tôi không phải là nhà phát triển Python có kinh nghiệm một chút nào đó nên có thể có một cách thành ngữ hơn về vấn đề này):
def general_catcher(task):
try:
task()
except SomeError1:
# do some uniformly-designed recovery stuff here
except SomeError2:
# do some other uniformly-designed recovery stuff here
...
[Hy vọng với một cái tên tốt hơn general_catcher
]. Trong ví dụ này, bạn có thể chuyển vào một hàm chứa tác vụ nào sẽ thực hiện nhưng vẫn được hưởng lợi từ hành vi bắt chung chung / thống nhất cho tất cả các loại ngoại lệ bạn quan tâm và tiếp tục mở rộng hoặc sửa đổi phần "việc cần làm" bạn thích từ vị trí trung tâm này và vẫn trong catch
bối cảnh thường được khuyến khích. Trên hết, chúng ta có thể giữ cho các trang web ném không liên quan đến mình với "phải làm gì" (bảo tồn khái niệm "người ném mù").
Nếu bạn thấy không có gợi ý nào ở đây hữu ích và dù sao cũng có một sự cám dỗ mạnh mẽ để đưa ra những ngoại lệ "phải làm gì", chủ yếu hãy lưu ý rằng điều này rất ít phản đối, cũng như có khả năng làm nản lòng một tư duy khái quát.