【问题标题】:Liskov substitution principle or encapsulation violationLiskov 替换原则或封装违规
【发布时间】:2018-04-27 11:48:29
【问题描述】:

在这篇文章中,我想向您展示一个包含几个 JS 类的小代码示例,并询问您,这段代码是因为LSP 还是可以的,还是它违反了封装原则。

此示例中的_framesMonitor 变量是我们在Job 类中使用的某个3-d 派对库vqt 的一个实例。 _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
    }
  }
}

【问题讨论】:

    标签: oop encapsulation solid-principles liskov-substitution-principle


    【解决方案1】:

    在这种情况下,Job 是一个具体的类,JobManager 直接依赖于它,因此只要您的意图是只有一种Job,它就可以知道Job 的细节。

    但是,如果您在概念上计划有许多不同的 Job 实现(无论语言是否支持显式接口),那么理想情况下,JobManager 应该尝试一般地处理所有 Job,并且最好不要依赖任何Job 详细信息。

    因此,JobManager 可能会捕获任何错误,但理想情况下不应根据任意错误详细信息驱动其工作流程。如果JobManager 必须知道一定程度的细节才能发出适当的补偿动作,那么您应该尝试提出一个标准化的JobFailureError(甚至是返回值),以提供必要的信息(它也可以携带低-用于记录目的的级别错误原因)。

    最后,如果您需要对每一种无法规范化的工作进行特殊处理,那么这将是一个权衡问题。

    为了使错误处理不受Job 的关注,您可以允许使用JobManager 注册特殊作业处理策略。尽管这种方法遵循开闭原则 (OCP),但它也是服务定位器的一种实现,有些人将其视为反模式。添加新的Job 实现时,您还需要记住添加相应的处理程序。

    例如

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

    如果您不介意错误处理程序的概念和Job 之间存在某种程度的耦合,那么您可以执行new SomeJob(errorHandler) 之类的操作,甚至可以将SomeJob 耦合到特定的处理程序。

    我通常会在这里选择服务定位器方法,但我不确定我们是否可以说它在所有类似情况下都是绝对最佳的。

    例如,如果您使用的是静态类型语言,也许使用double-dispatch 技术甚至pattern matching(如果可用)会更好,因为您可以获得编译时反馈。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-01-01
      • 1970-01-01
      • 2010-12-03
      • 2011-09-09
      • 2012-01-12
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多