Trong API của tôi, tôi có một hệ thống phân cấp ngoại lệ nhỏ, bắt nguồn từ std::exception
. Tôi có một lớp cơ sở Exception
, cung cấp mã lỗi, tệp, dòng và chức năng. Các trường hợp ngoại lệ cụ thể khác có nguồn gốc từ Exception
. Ví dụ, một lớp dẫn xuất bổ sung một mã lỗi cụ thể cho nền tảng, cũng như một trường xác định hàm nào trả về mã lỗi. Điều này giống như một phiên bản đơn giản của system_error
, nhưng tôi không thể sử dụng các tính năng C++ 11 (Tôi đang làm việc với VS2005 và không có Tăng cường).Trường hợp ngoại lệ tách từ định dạng nhật ký
Tôi cần đăng nhập những ngoại lệ này với lớp đăng nhập của mình. Tôi muốn các ngoại lệ được đăng nhập theo một định dạng nhất định. Sau khi đọc nhiều diễn đàn trực tuyến và đọc Boost's Error and Exception Handling Guidelines, tôi không nghĩ rằng chức năng what
của mỗi ngoại lệ hoặc bất kỳ chức năng ảo nào khác trong phạm vi Exception
, là nơi thích hợp để định dạng ngoại lệ cho việc ghi nhật ký. Do đó các hàm what
của tôi chỉ trả về tên của lớp.
Khi bắt ngoại lệ, tôi thường muốn loại trừ các ngoại lệ rất chung chung, thường là std::exception
và chuyển nó tới trình ghi nhật ký. Tôi không muốn bắt ngoại lệ cá nhân rất thường xuyên vì tôi đang cố gắng ngăn chặn các ngoại lệ thoát khỏi API (phần công khai của API của tôi nằm trong C) và có thể có một số ngoại lệ có thể xảy ra. Tôi muốn tránh mã như:
try { /* blah */ }
catch {DerivedException const& ex) { logger.log(ex); }
...
catch {Exception const& ex) { logger.log(ex); }
Vì vậy, trong lớp đăng nhập của tôi, chức năng log
tôi chấp nhận một đối số std::exception
. Sau đó, nó sử dụng typeid
để so sánh tham số với các lớp ngoại lệ khác nhau, truyền tới loại thích hợp và sau đó gọi hàm ghi nhật ký chuyên biệt cho loại ngoại lệ đó. Đây chính là kỹ thuật tương tự được mô tả in this other post.
tôi sử dụng typeid
thay vì dynamic_cast
vì dynamic_cast
có thể thành công đối với bất kỳ yếu hèn hợp lệ, và cho các mục đích bảo trì mã, tôi thực sự không muốn thứ tự của if
phát biểu của tôi trong log
chức năng để thành vấn đề.
Vì vậy, đây có phải là thiết kế phù hợp không? Nó cảm thấy sai với tôi bằng cách sử dụng typeid
như thế này, nhưng tôi nghĩ rằng tôi có lý do hợp lệ để làm điều đó. Tôi đã không nhìn thấy nhiều ngoại lệ xử lý "trong tự nhiên", vì chúng tôi chủ yếu làm việc với C, vì vậy tôi đã không nhìn thấy quá nhiều cách tiếp cận đối tượng. Có cách nào khác để tách biệt các ngoại lệ khỏi định dạng nhật ký của chúng mà tôi nên biết không?
EDIT: Những gì tôi đã quyết định để thực hiện
Tôi đã đề nghị sử dụng các mô hình khách truy cập, nhưng thích nghi nó vào hoàn cảnh của tôi. Tôi muốn bắt std::exception
, vì chúng có thể được ném cũng như của riêng tôi, nhưng định dạng thông điệp tường trình dựa trên loại ngoại lệ.
Mỗi lớp học ngoại lệ của tôi xuất phát từ lớp cơ sở Exception
và thực hiện chức năng ảo accept
. Tôi đã tạo một lớp ExceptionLogger
, thực hiện giao diện ExceptionVisitor
cung cấp các chức năng visit
.
Lớp LogFile
có phiên bản ExceptionLogger
, cũng như quá tải chức năng log
có tham số std::exception
. Trong hàm log
, tôi thử một số dynamic_cast
vào loại cơ sở của tôi, Exception
. Nếu nó thành công, tôi gọi hàm accept
của ngoại lệ, nếu không, tôi gọi hàm ExceptionLogger::visit(std::exception const&)
trực tiếp.Vì std::exception
không triển khai chức năng accept
của tôi, tôi cần dynamic_cast
để tôi có thể xác định xem có thể ghi nhật ký chi tiết hơn hay không.
tôi đã chọn để làm điều này thay vì một loạt các if
báo cáo kiểm tra typeid
vì:
- Đó là một mẫu thiết kế có tên mà tôi có thể tham khảo bảo trì trong tương lai để
Nếu một nhà bảo trì thêm một bắt nguồn ngoại lệ mới từ cơ sở
Exception
của tôi, nhưng quên thực hiện chức năngvisit
mới cho ngoại lệ đó, tôi sẽ vẫn nhận được nhật ký được triển khai cho cơ sởException
- một tệp, số dòng và chức năng.Nếu tôi đã thực hiện hàng loạt các
if
báo cáo, tôi sẽ đã phải rơi trở lại với hành vi khai thác gỗstd::exception
, mà chỉ là để in ra các kết quả củawhat
, hoặc tôi có thể đã thử mộtdynamic_cast
mộtException
.Tất nhiên tôi vẫn thích lỗi trình biên dịch hơn trong trường hợp này.
Cách khác là áp dụng mẫu Khách truy cập. –
@DDrmmr - Tôi đã sử dụng mẫu Khách truy cập. Đặt câu trả lời này thành một câu trả lời và tôi sẽ đánh dấu nó là đã được chấp nhận. –