Принцип подстановки Лисков (LSP), шаблон прокси и исключения

Предположим, у меня есть интерфейс и его конкретная реализация, которую использует клиентский код. Теперь, используя шаблон прокси, который реализует этот интерфейс, я мог направлять запросы к интерфейсу по сети. Конечно, сетевое соединение может не работать, что может вызвать исключение.

Клиентский код, использующий интерфейс, получит неожиданное исключение. Я предполагаю, что в этой ситуации нарушается принцип 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);
}

Должен ли я изменить интерфейс, чтобы разрешить распространение исключений?


person trenki    schedule 13.02.2015    source источник
comment
Почему вы считаете, что сбой соединения является нарушением принципа подстановки Лисков? Спросите себя, сколько у нас здесь обязанностей?   -  person Roman Ambinder    schedule 13.02.2015
comment
Исходный интерфейс не имеет ничего общего с доступом к сети, поэтому также не будет указывать какие-либо исключения, но реализация прокси, использующая сеть, делает это.   -  person trenki    schedule 13.02.2015
comment
Я думаю, что механизм распределения, используемый прокси-сервером в качестве зависимости (за кулисами), сбивает вас с толку. Вы можете попробовать абстрагировать его как зависимость от вашего прокси-интерфейса, и тогда все станет яснее.   -  person Roman Ambinder    schedule 13.02.2015


Ответы (1)


Учитывая, что вы пишете на Java, если вы хотите, чтобы ваш Interface был реализован таким образом, чтобы вызовы методов могли завершиться ошибкой, вам нужно будет сделать одну из двух вещей: либо

  • изменить методы Interface так, чтобы они вызывали проверенное исключение, или
  • заставить реализации вызывать непроверенные исключения.

Относительные преимущества и недостатки проверенных и непроверенных исключений подробно обсуждаются в SO и во всем Интернете. Я не много писал на Java в течение нескольких лет, но несколько лет назад была тенденция использовать только непроверенные исключения, чтобы избавить вызывающую сторону от необходимости их обрабатывать. Честные пользователи Ruby (я один из них) скажут вам, что они постоянно забывают обрабатывать случаи ошибок из-за своего нетипизированного языка и в конечном итоге обрабатывают их в исправлениях. Сейчас в моде Haskell, язык, в котором сигнатуры типов используются для ограничения поведения таким образом, что лагерь непроверенных исключений будет бежать куда подальше.

Я бы использовал проверенное исключение, чтобы убедиться, что вызывающая сторона обрабатывает возможные сбои. Однако я бы использовал не NetworkException, а что-то общее, например MethodFailureException (если бы мы знали, что делает Interface, мы могли бы выбрать лучшее имя), которое NetworkException могло бы расширить. Это избавляет вызывающего абонента от знания о реализации, но при этом позволяет ему обработать ошибку.

person Dave Schweisguth    schedule 09.02.2016