oop – Scala类型的多态性
我们正在重构一个继承的方法来使用类型类 – 我们希望将所有方法实现集中在一个地方,因为将它们分散在实现类中会使维护变得困难.但是,我们遇到了一些麻烦,因为我们对类型类很新.目前的方法定义为
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,同时使类型类的想法无法使用(待打开),而是以和类型(已知的所有子类型)结束. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |