Мы перерабатываем унаследованный method
, чтобы вместо этого использовать класс типа - мы хотели бы сконцентрировать все реализации method
в одном месте, поскольку их разброс между классами реализации затрудняет техническое обслуживание. Однако мы сталкиваемся с некоторыми проблемами, так как мы довольно новы, чтобы вводить классы. В настоящее время method
определяется какПолиморфизм с классами типа 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 + конкретных классов, иерархия неглубокий (abstract class SuperClass
->abstract class SubSuperClass
->abstract class SubSubSuperClass
->class ConcreteClass
это так глубоко, как он идет), и конкретный класс никогда не расширяет другой конкретный класс. (В фактической реализации, method
возвращает 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. Вызов method
на суперкласс, например.
val s: SuperClass = new Clazz1()
s.method
В идеале я хотел бы быть в состоянии сказать компилятору, что каждый подкласс SuperClass
имеет соответствующий неявный объект для method
в классе типа и так 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
как запечатанная черта.
Мы были бы открыты для альтернатив типа классов, которые позволили бы нам сконцентрировать method
код в одном месте. method
только вызываются из двух мест:
А. Других method
реализаций, например Clazz1
имеет val clazz2: Option[Clazz2]
, в этом случае method
реализация в Clazz1
будет что-то вроде
def method = super.method ++ /* Clazz1 method implementation */ ++
clazz2.map(_.method).getOrElse(Map())
B. Верхнего уровня Контроллер Play Framework (т.е. абстрактный класс, из которого наследуются все контроллеры), где мы определили три ActionBuilders
, которые вызывают method
, например
def MethodAction[T <: MethodTrait](block: Request[AnyContent] => T) = {
val f: Request[AnyContent] => SimpleResult =
(req: Request[AnyContent]) => Ok(block(req).method)
MethodActionBuilder.apply(f)
}
Я бы пришел к аналогичному выводу, но по другой причине. Но в любом случае, пока вы описали проблему, не могли бы вы также предложить решение? Мне интересно о ваших мыслях. – Vidya