Vererbung
Jeder Deskriptor listet seine Basistypen nach Namen. Registrierte Deskriptoren beantworten Subtyp-Fragen über Namen, ohne Laufzeitklassen, und genau das brauchen Plugin-Systeme und polymorphes Mapping.
Basistypen
Vom Compiler
baseTypes ist die Linearisierung, die der Compiler berechnet hat: Oberklassen und Traits, bis Any.
- reflect[Dog].baseTypes
- demo.Animal, java.lang.Object, scala.Matchable, scala.Any
- reflect[Dog].isSubTypeOf("demo.Animal")
- true
- reflect[Dog].isSubTypeOf("demo.Entity")
- false
Abfragen
ClassDescriptor als Verzeichnis
Das Objekt ClassDescriptor liest die globale Registry: einen Deskriptor nach Namen finden, die Subtypen eines Typs auflisten oder die Zuweisbarkeit zwischen zwei Namen prüfen.
- ClassDescriptor.maybeForName("demo.Cat").map(_.simpleName)
- Some(Cat)
- subTypesOf("demo.Animal") without Animal itself
- List(Cat, Dog)
- ClassDescriptor.isAssignableFrom("demo.Cat", "demo.Animal")
- true
scala
ReflectRegistry.register(() => Dog("Rex"))
ReflectRegistry.register(() => Cat("Tom"))
ClassDescriptor.subTypesOf("demo.Animal")
ClassDescriptor.isAssignableFrom("demo.Cat", "demo.Animal")
Polymorphie
Erzeugen über einen Namen von außen
Ein Typname aus JSON, einer URL oder einer Konfigurationsdatei wird zur Instanz, und die Prüfung, dass es ein Animal ist, passiert, bevor etwas erzeugt wird.
- create("demo.Cat").map(_.name)
- Some(Tom)
- create("demo.Query")
- None
scala
def create(typeName: String): Option[Animal] =
Option.when(ClassDescriptor.isAssignableFrom(typeName, "demo.Animal"))(typeName)
.flatMap(ReflectRegistry.createInstance)
.collect { case animal: Animal => animal }