Liskov替换原则(LSP),代理模式和异常

3
假设我有一个接口和它的具体实现,客户端代码使用该实现。现在,使用实现该接口的代理模式,可以将对接口的请求路由到网络上。网络连接可能会失败,这可能会引发异常。
使用接口的客户端代码将会收到意外的异常。我猜在这种情况下违反了LSP原则。
但是如果不允许将网络异常传播出接口,如何处理这种情况呢?
以下是一些Java代码,以澄清我的意思:
interface Interface
{
    abstract void method1();
    abstract void method2();
    abstract void method3();
}

class Implementation implements Interface
{
    void method1();
    void method2();
    void method3();
}

class ProxyOverNetwork implements Interface
{
    // I can't add the NetworkException as it is not part of the Interface 
    // and would violate LSP, but how to handle the network problems then,
    // when the ProxyOverNetwork might not be the right place to do so?

    void method1() throws(NetworkException);
    void method2() throws(NetworkException);
    void method3() throws(NetworkException);
}

我需要更改接口以使异常传播出去吗?

你为什么认为连接失败违反了Liskov替换原则? 问问自己我们在这里有多少个责任? - Roman Ambinder
原始接口与网络访问无关,因此也不会指定任何异常抛出,但使用网络的代理实现会这样做。 - trenki
我认为代理后台使用的依赖分发机制是让你感到困惑的原因。你可以尝试将其抽象为代理接口的一个依赖项,这样事情就会更加清晰了。 - Roman Ambinder
1个回答

0

假设你正在使用Java编写代码,如果你希望你的Interface在实现方法调用时可能失败,你需要做以下两件事之一:

  • 更改Interface的方法,使其引发已检查异常,或者
  • 使实现引发未检查异常。

已检查异常和未检查异常的相对优缺点在SO和互联网上都有详细讨论。我已经好几年没有写过太多Java了,但是几年前的趋势是仅使用未检查异常,以节省调用者处理异常的麻烦。诚实的Ruby程序员(我就是其中之一)会告诉你,由于他们的无类型语言,他们经常忘记处理错误情况,并最终在热修复中处理它们。Haskell现在很流行,这是一种使用类型签名来限制行为的语言,这将使未检查异常阵营惊恐万分。

我会使用已检查异常来确保调用者处理可能的失败。但我不会使用像NetworkException这样的特定异常,而是使用一些通用的异常,比如MethodFailureException(如果我们知道Interface的作用,我们可以选择更好的名称),然后让NetworkException继承它。这样可以避免调用者了解实现细节,同时仍然允许他们处理错误。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接