Принцип подстановки Лискова или нарушение инкапсуляции

В этом посте я хочу показать вам небольшой пример кода с несколькими классами JS и спросить вас, подходит ли этот код из-за LSP или он нарушает принципы инкапсуляции.

_framesMonitor переменная в этом примере является экземпляром какой-то сторонней библиотеки vqt что мы используем внутри Job учебный класс. _framesMonitor.stopListen() может бросать исключения, особенно vqt.Errors.ProcessExitError,

В этом примере ниже, можно ли vqt.Errors.ProcessExitError введите в JobManager класс (и это нормально из-за LSP) или нарушает инкапсуляцию, раскрывая внутренние детали реализации.

// Job.js
class Job {
  constructor() {
     this._framesMonitor = new FramesMonitor();
  }

  async stop() {
      await this._framesMonitor.stopListen();
  }
}

// JobsManager.js
class JobsManager {
  async deleteJob() {
    try {
      await job.stop();
    } catch(err) {
      // vqt.Errors.ProcessExitError here
    }
  }
}

1 ответ

В этом случае Job это конкретный класс и JobManager зависит от него напрямую, поэтому можно знать специфику Job до тех пор, пока ваше намерение состоит в том, чтобы иметь только один вид Job,

Однако, если вы концептуально планируете иметь много разных Job реализации (поддерживает ли язык явные интерфейсы или нет), то в идеале JobManager должен попытаться лечить всех Job в общем и должно делать это лучше не зависеть ни от каких Job подробности.

Следовательно, JobManager может поймать любую ошибку, но в идеале не должен управлять ее рабочим процессом, основываясь на произвольных деталях ошибки Если JobManager должен знать некоторый уровень детализации для принятия соответствующих компенсирующих действий, тогда вы должны попытаться придумать нормализованный JobFailureError (или даже возвращаемое значение), которое предоставляет необходимую информацию (оно также может содержать причину ошибки низкого уровня для целей регистрации).

Наконец, если вам как-то нужна особая обработка для каждого вида работ, которые не могут быть нормализованы, тогда это будет вопрос компромиссов.

Не допускать обработки ошибок Job проблемы, которые вы могли бы разрешить регистрацию специальных стратегий обработки работы с JobManager, Хотя этот подход придерживается принципа Open-Closed принцип (OCP), он также является реализацией сервисного локатора, который некоторые считают анти-паттерном. При добавлении нового Job реализации, которые вы также должны помнить, чтобы добавить соответствующий обработчик.

Например

jobManager.registerHandler('some-job-type', function (job) {
    //Special handling code job of some-job-type
});

Если вы не возражаете против некоторого уровня связи между концепцией обработчика ошибок и Job тогда вы могли бы сделать что-то вроде new SomeJob(errorHandler) или даже имея SomeJob пара к конкретному обработчику.

Я бы обычно использовал здесь подход Service Locator, но я не уверен, можем ли мы сказать, что он является абсолютным лучшим в каждом подобном сценарии.

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

Другие вопросы по тегам