当类依赖于隐式时,是否存在将类转换为Object的惯用方法?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了当类依赖于隐式时,是否存在将类转换为Object的惯用方法?相关的知识,希望对你有一定的参考价值。

我是Scala的新手。

我有一系列执行UI测试的测试类,以及一系列包含可重用辅助方法的类。

示例测试类:

class MyCoolTestClass extends FreeSpec {

    //Note:  This driver needs to be configurable by the test in some way.
    implicit val driver:WebDriver = new ChromeDriver()

    val myCoolPage = new MyCoolPage

    //Tests below rely on myCoolPage methods
}

示例助手类:

class MyCoolPage(implicit driver:WebDriver) {
    def clickElement1(){
     //relies on driver
    }
    def assertElement2Enabled(){
     //relies on driver
    }
}

现在,没有一个辅助类实际上具有可变状态。这使我想将它们从classes转换为objects。

但是,我能弄清楚如何做到这一点的唯一方法是为每个方法添加一个implicit WebDriver参数。这很有效,但很难看。有没有更简洁的方法来实现我想要的东西?或者,是否有一种更惯用的方式来完全组织这个测试类/助手方法关系?

答案

我认为,正如你所问,没有惯用的方法将classes转换为objects。以下是我对以下原因的看法:

你在driver中声明了一个属性MyCoolClass,你正在使用这些方法。因此你的class实际上有状态。 WebDriverstate injected进入MyCoolPage。根据注入的WebDriver的实现,处理方法调用的方式可能会有所不同。

要克服这一点,你需要将WebDriver作为你的每个方法的隐含参数,正如你自己发现的那样。但是,这将允许在运行时从外部替换驱动程序。这会违反Open-Closed-Principle,我认为这比使用你的class构造更不惯用。

如果将来再次遇到此问题,您可能会尝试在不使用implicit的情况下编写代码。如果它仍然是将class改为object的合适方式,那么你可能会很高兴。

另一答案

您可以将帮助类更改为对象,并仍然为成员方法提供implicit值。

object MyCoolPage {

  private val driver :WebDriver = implicitly[WebDriver]

  def clickElement1() = ???          //relies on driver
  def assertElement2Enabled() = ???  //relies on driver
}

但随后implicit声明必须退出测试类。想到两种可能性:WebDriver对象......

object WebDriver {
  implicit val wd :WebDriver = new ChromeDriver()
  ...

......或在专用物体中。

object MyCoolPage {
  import MyTestImplicits._
  private val driver :WebDriver = implicitly[WebDriver]
  ...

总而言之,我不相信它会值得付出努力。

另一答案

考虑将MyCoolPage转换为具有抽象隐式驱动程序字段的特征,如此

trait MyCoolPage {
  implicit val driver: WebDriver

  def clickElement1() = {
    //relies on driver
  }

  def assertElement2Enabled(){
    //relies on driver
  }
}

然后让MyCoolTestClass扩展MyCoolPage并使用自定义配置的驱动程序覆盖driver字段,如下所示

class MyCoolTestClass extends FreeSpec with MyCoolPage {
  override implicit val driver: WebDriver = new ChromeDriver()

  //Tests below rely on myCoolPage methods
}

现在MyCoolTestClass可以访问MyCoolPage中的每个方法,并且这些方法不需要隐式驱动程序参数。

另一答案

现在,没有一个辅助类实际上具有可变状态。这使我想将它们从classes转换为objects。

但他们确实有州。是的,它是不可变的,但大多数案例类的状态也是如此,Options,Lists ......它们都不应该被转换成objects。我不认为有一个解决方案比你开始时更好。

但是,这里有一个选项:将辅助对象嵌套在超类中:

abstract class AbstractTestClass extends FreeSpec {
  // may optionally be implicit or non-abstract
  val driver: WebDriver 

  object MyCoolPage {
    def clickElement1(){
      //relies on driver
    }
    def assertElement2Enabled(){
      //relies on driver
    }
  }

  object MyCoolPage2 ...
}

class MyCoolTestClass extends AbstractTestClass {
  override val driver: WebDriver = new ChromeDriver()

  // can use MyCoolPage methods
}

请注意,objects是懒洋洋地加载的,所以如果MyCoolTestClass不使用MyCoolPage2它将不会支付它。权衡是必须在单个文件中定义所有辅助类。

以上是关于当类依赖于隐式时,是否存在将类转换为Object的惯用方法?的主要内容,如果未能解决你的问题,请参考以下文章

Python 之禅“显式胜于隐式”

当我们在范围内存在多个不明确的隐式时,Scala 编译如何选择隐式

无法将float类型隐式转换为int。存在显式转换(您是否缺少演员表?)

Scala隐式转换

Scala隐式转换

转载:深入理解Scala的隐式转换系统