加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > 安全 > 正文

oop – Scala类型的多态性

发布时间:2020-12-16 19:18:08 所属栏目:安全 来源:网络整理
导读:我们正在重构一个继承的方法来使用类型类 – 我们希望将所有方法实现集中在一个地方,因为将它们分散在实现类中会使维护变得困难.但是,我们遇到了一些麻烦,因为我们对类型类很新.目前的方法定义为 trait MethodTrait { def method: Map[String,Any] = // defa
我们正在重构一个继承的方法来使用类型类 – 我们希望将所有方法实现集中在一个地方,因为将它们分散在实现类中会使维护变得困难.但是,我们遇到了一些麻烦,因为我们对类型类很新.目前的方法定义为

trait MethodTrait {
  def method: Map[String,Any] = // default implementation
}

abstract class SuperClass extends MethodTrait {
  override def method = super.method ++ // SuperClass implementation
}

class Clazz extends SuperClass {
  override def method = super.method ++ // Clazz implementation
}

等等,总共有50个具体类,层次结构相当浅(抽象类SuperClass – >抽象类SubSuperClass – >抽象类SubSubSuperClass – >类ConcreteClass就像它一样深),和具体类永远不会扩展另一个具体类. (在实际实现中,方法返回Play Framework JsObject而不是Map [String,Any].)我们试图用类型类替换它:

trait MethodTrait[T] {
  def method(target: T): Map[String,Any]
}

class MethodType {
  type M[T] = MethodTrait[T]
}

implicit object Clazz1Method extends MethodTrait[Clazz1] {
  def method(target: Clazz1): Map[String,Any] { ... }
}

implicit object Clazz2Method extends MethodTrait[Clazz2] {
  def method(target: Clazz2): Map[String,Any] { ... }
}

// and so on

我遇到了两个问题:

A.模仿先前实现中的super.method功能.目前我正在使用

class Clazz1 extends SuperClass

class Clazz2 extends SubSuperClass

private def superClassMethod(s: SuperClass): Map[String,Any] = { ... }

private def subSuperClassMethod(s: SubSuperClass): Map[String,Any] = {
  superClassMethod(s) ++ ...
}

implicit object Clazz1Method extends MethodTrait[Clazz1] {
  def method(target: Clazz1): Map[String,Any] = { 
    superClassMethod(target) ++ ... 
  }
}

implicit object Clazz2Method extends MethodTrait[Clazz2] {
  def method(target: Clazz2): Map[String,Any] = { 
    subSuperClassMethod(target) ++  ... 
  }
}

但这很难看,如果我不小心将方法调用到层次结构太远,我就不会收到警告或错误,例如如果Clazz2调用superClassMethod而不是subSuperClassMethod.

B.对超类的调用方法,例如

val s: SuperClass = new Clazz1()
s.method

理想情况下,我希望能够告诉编译器SuperClass的每个子类都有类型类中方法的对应隐式对象,因此s.method是类型安全的(或者如果我’,我将得到编译时错误)我忽略了为SuperClass的子类实现一个相应的隐式对象,但是我已经能够想到的是

implicit object SuperClassMethod extends MethodTrait[SuperClass] {
  def method(target: SuperClass): Map[String,Any] = { 
    target match {
      case c: Clazz1 => c.method
      case c: Clazz2 => c.method
      ...
    }
  }
}

这是丑陋的,如果我省略了一个类,我不会给我编译时警告或错误,因为我不能将SuperClass定义为密封特征.

我们愿意接受类型类的替代方法,这样我们就可以将方法代码集中在一个地方.方法只能从两个地方调用:

A.其他方法实现,例如Clazz1有一个val clazz2:Option [Clazz2],在这种情况下,Clazz1中的方法实现会像

def method = super.method ++ /* Clazz1 method implementation */ ++ 
  clazz2.map(_.method).getOrElse(Map())

B.顶级Play Framework控制器(即所有控制器继承的抽象类),我们在其中定义了三个调用方法的ActionBuilder,例如:

def MethodAction[T <: MethodTrait](block: Request[AnyContent] => T) = {
  val f: Request[AnyContent] => SimpleResult = 
    (req: Request[AnyContent]) => Ok(block(req).method)

  MethodActionBuilder.apply(f)
}

解决方法

我认为类型类与您的场景不兼容.当类型不相交时,它们很有用,但实际上要求实例反映超类型/子类型层次结构并且不是独立的.

通过这种重构,您只是创建了挑选错误实例的危险:

trait Foo
case class Bar() extends Foo

trait HasBaz[A] { def baz: Set[Any] }

implicit object FooHasBaz extends HasBaz[Foo] { def baz = Set("foo") }
implicit object BarHasBaz extends HasBaz[Bar] { def baz = FooHasBaz.baz + "bar" }

def test[A <: Foo](x: A)(implicit hb: HasBaz[A]): Set[Any] = hb.baz

val bar: Foo = Bar()
test(bar) // boom!

所以你最终用SuperClassMethod中的模式匹配器重写了多态分派.你基本上去OO – > FP – > OO,同时使类型类的想法无法使用(待打开),而是以和类型(已知的所有子类型)结束.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读