提问人:Ahzam Ahmed 提问时间:5/11/2023 更新时间:5/20/2023 访问量:72
如何在新错误类型的错误处理中实现开闭原则?
How to implement the Open-Closed Principle in error handling for new error types?
问:
在给定的 JavaScript 代码片段中,有两个函数 handleClientError 和 handleServerError,分别处理客户端和服务器端错误。handleError 函数用于根据传递给它的 error 参数确定需要处理的错误类型。
但是,如果需要处理新的错误类型(假设 ABCSideError),则代码当前需要修改 handleError 函数,以便为 ABCSideError 类型添加新的条件检查,并定义一个新函数来处理它。
如何避免为每个新错误类型添加新检查和函数的手动过程,意味着添加新的错误类型只需要定义一个新函数,而不需要其他任何内容。
try{
// some code
}catch(error)
{
handleError(error)
}
function handleError(error) {
if (error instanceof ClientSideError) {
return handleClientError(error);
}
return handleServerError(error);
}
function handleClientError(error) {
// handle error from client side
}
function handleServerError(error) {
// handle error from server side
}
尽管进行了多次尝试,但我仍无法找到不需要 if-else 或 switch 语句来动态处理新错误类型的实现。
答:
开闭原则与“if-else”或“switch”语句无关。OCP 规定,类应该开放以进行扩展,但可以关闭以进行修改。换句话说,不要让新行为从你当前的课堂中逃脱,从而破坏你的客户。就是这样。
通过封装错误处理并且不引发或重新引发新错误,您已经实现了 OCP 的目标,即不对当前依赖此代码的客户端进行重大更改。
避免使用“if-else”和“switch”语句是重构过程的一部分,在重构过程中,它们被视为“代码异味”,表明某种形式的重构可能是可取的。但这并不完全适用于这里,因为这是外部库的错误处理程序,这些库会引发超出您控制范围的错误。您没有机会修改它们。相反,错误处理程序将成为封装它们的位置,因此新错误不会违反 OCP。如果这需要额外的“if instanceof”测试,那么这就是你必须编写的内容。
下面是一个示例。如果您有大量且不断增长的错误类型,这可能是一种方法。
class ErrorHandler {
handleError(error) {
// This will be overridden in subclasses
}
}
class ClientErrorHandler extends ErrorHandler {
handleError(error) {
if (!(error instanceof ClientSideError)) {
return null;
}
// handle error from client side
}
}
class ServerErrorHandler extends ErrorHandler {
handleError(error) {
if (!(error instanceof ServerSideError)) {
return null;
}
// handle error from server side
}
}
然后,在调用该函数时,您将 DI 处理程序数组。这样,即使你有新的具体错误处理程序,riskyOperation 也不需要修改。
function riskyOperation(errorHandlers) {
try {
// do stuff ...
} catch (error) {
for (let handler of errorHandlers) {
if (handler.handleError(error)) {
break;
}
}
}
}
riskyOperation([new ClientErrorHandler(), new ServerErrorHandler()]);
OCP 的关键概念包括:
- 抽象化
- 多态性
- 客户端和服务器/服务的范围
- 地
然后,即使服务数量增加,客户端也不需要修改。
消费者代码:
try {
// ...some code...
} catch(error) {
handleError(error)
}
错误处理中心:
function handleError(error) {
for (let handler of errorHandlerRegistry.handlers) {
let r = handler(error);
if (r) {
return r;
}
}
// ...some default behavior...
}
let errorHandlerRegistry = {
handlers: [],
register: function(handler) {
this.handlers.push(handler);
},
};
客户端错误处理程序:
function handleClientError(error) {
// ...handle error from client side...
}
errorHandlerRegistry.register(handleClientError);
服务器错误处理程序:
function handleServerError(error) {
// ...handle error from server side...
}
errorHandlerRegistry.register(handleServerError);
ABC 错误:
function handleAbcError(error) {
// ...handle error from ABC side...
}
errorHandlerRegistry.register(handleAbcError);
评论
errorHandlers
errorHandlers[error.constructor.name](error);