Do tego służy .
Myślę, że interfejs API do odczytywania ułatwia sortowanie potrzebnych informacji (np. Do filtrowania, ale nie do wysyłania zapytań do modułu ładującego klasy).
Jeśli przez wyrażenie "przeszukiwanie załadowanych klas", naprawdę masz na myśli klasy, które są już załadowane, zobacz this question, aby je uzyskać.
Można sobie wyobrazić bibliotekę widgetów z inicjatorem, który zapewnia, że wszystkie klasy widżetów, o których wie, są załadowane. Wtedy klient musi tylko znać inicjator.
Test typu jest taki sam.
val need = typeOf[Whatsit[Cog]]
for (x <- (ServiceLoader load classOf[Whatsit[_]]).asScala) {
val im = currentMirror reflect x
if (im.symbol.toType weak_<:< need)
Console println s"$x is what I need"
else
Console println s"$x is not what I need, I'm looking for a $need"
}
Jeżeli szukasz czegoś z parametrami Typ:
trait Whatsit[+A <: Widget] {
def widget: A
}
class Engine extends Whatsit[Cog] {
def widget = new Cog
}
class FlyWheel extends Whatsit[Sprocket] {
def widget = new Sprocket
}
Próbka:
[email protected] is what I need
[email protected] is not what I need, I'm looking for a widgets.Whatsit[widgets.Cog]
W przypadku minęło dziesięć lat, odkąd został użyty ServiceLoader
, a kto nie potrzebujesz odświeżenia:
[email protected]:~/tmp$ ls -R META-INF
META-INF:
MANIFEST.MF services
META-INF/services:
widgets.Whatsit widgets.Widget
[email protected]:~/tmp$ cat META-INF/services/widgets.Widget
widgets.Cog
widgets.Sprocket
[email protected]:~/tmp$ cat META-INF/services/widgets.Whatsit
widgets.Engine
widgets.FlyWheel
Stuff:
package widgets
trait Widget {
def turn(): Int
override def toString = s"Widget ${getClass.getSimpleName}"
}
class Cog extends Widget {
def turn() = 5
}
class Sprocket extends Widget {
def turn() = 10
}
trait Whatsit[+A <: Widget] {
def widget: A
override def toString = s"Whatsit ${getClass.getSimpleName} of $widget"
}
class Engine extends Whatsit[Cog] {
def widget = new Cog
}
class FlyWheel extends Whatsit[Sprocket] {
def widget = new Sprocket
}
Porównując Scala i Java. Zamierzałem dowiedzieć się, ile LOC do getGenericInterfaces
i znaleźć to, co chcesz w Scali, ale potem położyłem kres ćwiczeniu.
package findwidgets
import reflect._
import reflect.runtime.universe._
import reflect.runtime.currentMirror
import scala.collection.JavaConverters._
import java.util.ServiceLoader
object Test extends App {
import widgets.{ Widget, Whatsit, Cog }
val ws = (ServiceLoader load classOf[Widget]).asScala
for (w <- ws) {
Console println s"Turn a ${w.getClass} by ${w.turn}"
}
val need = typeOf[Whatsit[Cog]]
for (x <- (ServiceLoader load classOf[Whatsit[Cog]]).asScala) {
val im = currentMirror reflect x
if (im.symbol.toType weak_<:< need)
Console println s"$x is what I need"
else
Console println s"$x is not what I need, I'm looking for a $need"
// java says:
if (classOf[Whatsit[Cog]] isAssignableFrom x.getClass)
Console println s"Um, OK, I'll take the $x"
else
Console println s"${classOf[Whatsit[Cog]]} isn't ass'able from ${x.getClass}"
}
}
Czy to nie wymaga, że programista jawnie deklaruje swój interfejs jako usługę i wymienia wszystkie jego implementacje w "META-INF/services/..."? – ghik
Tak, więc chodzi o to, że biblioteka mówi ci, co oferuje. Zamiast próbować skanować znany wszechświat pod kątem widżetów, istnieje zasób w znanej lokalizacji, który można zapytać o dany moduł ładujący klasy. Wkleiłem inne kawałki do FYI. –
Doskonale! Dzięki som! Dokładnie tego potrzebowałem. – Doswell