2014-09-19 24 views
5

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_castdynamic_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ì:

  1. Đó 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 để
  2. 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ăng visit 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ủa what, hoặc tôi có thể đã thử một dynamic_cast một Exception .

    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.

+1

Cách khác là áp dụng mẫu Khách truy cập. –

+0

@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. –

Trả lời

1

Một giải pháp đơn giản là tính lại ngoại lệ của bạn trong phương pháp định dạng trung tâm (xem thêm this answer). Sau đó, bạn có thể nắm bắt từng loại ngoại lệ và định dạng nó.

class Exception : public std::exception {}; 
class DerivedException : public Exception {}; 
void LogThrownException(); 

void DoSomething() 
{ 
    try 
    { 
     // Do something, might throw ... 
    } 
    catch (...) 
    { 
     LogThrownException(); 
    } 
} 

void LogThrownException() 
{ 
    try 
    { 
     throw; 
    } 
    // Order is important to catch all derived types. 
    // Luckily the compiler should warn, if a type is hidden. 
    catch (DerivedException&) 
    { 
     std::cout << "DerivedException"; 
    } 
    catch (Exception&) 
    { 
     std::cout << "Exception"; 
    } 
    catch (std::exception&) 
    { 
     std::cout << "std::exception"; 
    } 
    // ... 
    catch (...) 
    { 
     std::cout << "Unknown\n"; 
    } 
} 
+0

câu trả lời khác mà bạn đề cập có thể bị xóa bất kỳ lúc nào, vì vậy, mô tả ở đây sthing – manetsus

+0

Cảm ơn bạn đã gợi ý, tôi đã chỉnh sửa câu trả lời của mình. Tôi mới ở đây và nghĩ rằng có lẽ tốt hơn là không sao chép. – Djan

+0

Đó là một giải pháp đơn giản hơn nhiều. Thật không may là quá muộn để thực hiện nó, nhưng tôi thích nó và sẽ ghi nhớ nó trong tương lai. –

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