构造函数参数与抽​​象成员(Class 与抽象Class)

Constructor Parameters vs Abstract Members (Class vs Abstract Class)

我什么时候应该使用抽象 class 与常规 class?更具体地说,我试图了解何时应该优先使用构造函数参数而不是抽象成员。

例如:

sealed trait Client

abstract class BaseService {
  def client: Client
}

class Service extends BaseService {
  val client = ???
}

sealed trait Client

class BaseService(client: Client) {}

class Service extends BaseService(client = ???)

据我所知,两者都是有效的。

正如@Luis Miguel 所说,当您想声明一组需要由子classes and/or 共享实现的通用方法时,请使用抽象classes所有子 classes.

都将使用的一些有限功能

下面,我列出了一些我认为您应该将依赖项传递给构造函数而不是在 classes/base-classes 中定义它们的原因。

使用依赖注入

(恕我直言)最好为构造函数提供正常运行所需的依赖项 AKA dependency injection

避免紧耦合

当您在 class 或构造函数中声明依赖项时,您 您的 Service 与依赖项的特定实现紧密耦合,这并不理想,是 considered an antipattern.

接口编程,而不是实现

注入依赖项为您提供了更大的灵活性,因为您没有耦合到特定的实现。 只要您的代码依赖于 interface/trait/abstract-class(从而避免紧耦合),这就是事实。

当您的 class 依赖于 interface/trait/abstract-class 时,您可能会非常强大,因为您可以传递模拟、空操作或客户端的不同策略。所以确保你 "Program to interfaces, not implementations".