GENESIS DI
OBIETTIVI
-
Composizione di oggetti attraverso dependency injection
- Creazione di un oggetto a partire da una sua descrizione testuale con struttura gerarchica
-
Risoluzione ricorsiva dei collaboratori nel processo di creazione di un oggetto
- Integrazione di oggetti da librerie indipendenti
TERMINOLOGIA
SERVICE
Un servizio è un oggetto a cui viene attribuito un nome .
Ha un determinato tipo , che in base all'oggetto può essere:
- la sua classe;
- una sua superclasse;
- un'interfaccia implementata.
Tipo e nome identificano univocamente un servizio.
TERMINOLOGIA
SERVICE CONFIGURATION
Un servizio ha un insieme di parametri necessari alla sua configurazione.
I nomi e i valori dei parametri sono rappresentati come stringhe.
Un servizio viene parametrizzato attraverso una mappa in cui sono associati valori ai nomi dei parametri.
TERMINOLOGIA
SERVICE COLLABORATORS
Un servizio può necessitare che alcuni collaboratori gli vengano iniettati per poter usarne le funzionalità.
Ad ogni collaboratore è assegnato un ruolo, il cui nome è rappresentato come stringa, analogo al nome di un parametro della configurazione.
Un collaboratore può a sua volta avere collaboratori.
SERVICE DESCRIPTOR
RAPPRESENTAZIONE
ServiceDescriptor è la classe che rappresenta la descrizione testuale di un servizio, contenente i campi:
-
name: nome attribuito al servizio
-
configuration: coppie di stringhe parametro-valore
- collaborators: mappa che associa a un ruolo un descrittore di un collaboratore
SERVICE DESCRIPTOR
DEFINIZIONE
public class ServiceDescriptor {
public final String name;
public final Map<String, String> configuration;
public final Map<String, ServiceDescriptor> collaborators;
}
SERVICE DESCRIPTOR
GERARCHIA DI SERVIZI
Considerando i descrittori di servizi come nodi è possibile costruire un albero che rappresenti la gerarchia di composizione dei vari oggetti descritti.
Alla radice si trova il descrittore del servizio che si vuole utilizzare.
Le foglie sono servizi che non richiedono l'iniezione di alcun collaboratore.
SERVICE DESCRIPTOR
ESEMPIO
{
name: "dataMapper",
configuration: {
inputFile: "src/main/resources/file.csv",
outputFile: "target/generated-sources/file.json"
}, collaborators: {
reader: {
name: csv",
configuration: {
skipBlankLines: "true"
}
}, writer: {
name: "json"
}
}
}
SERVICE FACTORY
DEFINIZIONE
Un servizio viene istanziato attraverso una factory .
public interface ServiceFactory<S> {
S create(ServiceDescriptor service);
}
SERVICE CONTEXT
DEFINIZIONE
Un
C
ontext
contiene factory di servizi e si occupa di istanziare un servizio costruendo ricorsivamente i collaboratori.
public interface Context {
<S> S generate(Class<S> serviceType, ServiceDescriptor service);
<S> Map<String, ServiceFactory<S>> load(Class<S> serviceType);
}
CONFIGURATION
OBIETTIVI
- Definizione di un servizio e implementazione della sua logica di istanziazione rappresentabili in modo conciso
- Raggruppamento di servizi in moduli configurabili
- Possibilità di usare congiuntamente moduli caricati automaticamente dal classpath e moduli configurabili istanziati manualmente
CONFIGURATION
RAPPRESENTAZIONE
Una factory può essere definita a partire da un metodo usando le opportune annotazioni (mostrate in seguito).
Il nome del metodo rappresenta il nome del servizio, il tipo restituito diventa il tipo del servizio.
Gli argomenti del metodo possono assumere un diverso significato in base alle annotazioni usate.
CONFIGURATION
ANNOTAZIONI ARGOMENTI
-
@Parameter: indica che l'argomento va valorizzato recuperando dalla configurazione del servizio il valore del parametro col nome indicato
- @Role: richiede che come argomento sia passato un collaboratore, istanziato usando come descrittore quello col ruolo indicato
CONFIGURATION
ESEMPIO
public class ActivationFunctionConfiguration {
public ActivationFunction tanh() {
return new HyperbolicTangent();
}
public ActivationFunction logistic() {
return new LogisticFunction();
}
public ActivationFunction scale(
@Role("inner") ActivationFunction inner,
@Parameter("scale") String scale) {
return new Scale(inner, Double.parseDouble(scale));
}
}
CONFIGURATION
ESEMPIO
Implementazione diretta di una factory.
public class ScaleFactory implements ServiceFactory<ActivationFunction> {
private final Context context;
public ActivationFunction create(ServiceDescriptor service) {
return new Scale(
context.create(service.collaborators.get("inner"),
Double.parseDouble(service.configuration.get("scale"));
}
}
CONFIGURATION
ESEMPIO
Context context = new ConfigurationContext(Arrays.asList(
new ActivationFunctionConfiguration()
).iterator());
ServiceDescriptor scaledTanh = new ServiceDescriptor(
"scale",
Collections.singletonMap("scale", "1.15"),
Collections.singletonMap("inner", new ServiceDescriptor(
"tanh",
Collections.emptyMap(),
Collections.emptyMap())));
ActivationFunction function = context
.generate(ActivationFunction.class, scaledTanh);
CONFIGURATION
CARICAMENTO AUTOMATICO
Utilizzando come marker interface
Configuration
è possibile caricare tutte le sue implementazioni presenti nel classpath attraverso la classe
ServiceLoader
.
public class ActivationFunctionConfiguration implements Configuration { ... }
Iterable<Configuration> configurations = ServiceLoader
.load(Configuration.class);
Context context = new ConfigurationContext(configurations.iterator());
MAVEN
INTEGRAZIONE
Maven permette di configurare un suo plugin attraverso il descrittore di progetto pom.xml.
Si possono quindi descrivere uno o più servizi usando l'xml per rappresentarne la gerarchia di collaboratori.
MAVEN
ESEMPIO
<configuration>
<trainingMethod>
<name>batchBackPropagation</name>
<configuration>
<learningRate>0.1</learningRate>
<momentum>0.1</momentum>
<tolerance>0.01</tolerance>
</configuration>
<collaborators>
<logger>
<name>maven</name>
</logger>
</collaborators>
</trainingMethod>
</configuration>
Genesis DI
By labes
Genesis DI
Breve presentazione della libreria Genesis: https://bitbucket.org/0xdeadc0de/genesis
- 1,005