Ho provato a usare il motivo a torta nel mio progetto e mi è piaciuto molto, ma c'è un problema che mi dà fastidio.Modello di torta alla Scala per oggetti con diverse durate
Il modello di torta è facile da usare quando tutti i componenti hanno la stessa durata. Basta definire più tratti-componenti, estenderli mediante tratti-implementazione e quindi combinare queste implementazioni all'interno di un oggetto, e tramite i tipi di autodiagnosi tutte le dipendenze vengono automaticamente risolte.
Ma supponiamo di avere un componente (con le sue dipendenze) che può essere creato come conseguenza dell'azione dell'utente. Questo componente non può essere creato all'avvio dell'applicazione perché non ci sono ancora dati per esso, ma dovrebbe avere una risoluzione di dipendenza automatica al momento della creazione. Un esempio di tale relazione di componenti è la finestra principale della GUI e i suoi sotto-argomenti complessi (ad esempio una scheda nel riquadro del blocco note) che vengono creati su richiesta dell'utente. La finestra principale viene creata all'avvio dell'applicazione e alcuni sottogruppi vengono creati quando l'utente esegue un'azione.
Questo è facilmente fatto in framework DI come Guice: se voglio più istanze di qualche classe, io inietto solo un Provider<MyClass>
; quindi chiamo il metodo get()
su quel provider e tutte le dipendenze di MyClass
vengono risolte automaticamente. Se MyClass
richiede alcuni dati calcolati dinamicamente, posso usare l'estensione inject assistita, ma il codice risultante si riduce a un provider/factory. Anche il concetto correlato, gli ambiti, aiuta.
Ma non riesco a pensare a un buon modo per farlo usando un motivo a torta. Attualmente sto usando qualcosa di simile:
trait ModelContainerComponent { // Globally scoped dependency
def model: Model
}
trait SubpaneViewComponent { // A part of dynamically created cake
...
}
trait SubpaneControllerComponent { // Another part of dynamically created cake
...
}
trait DefaultSubpaneViewComponent { // Implementation
self: SubpaneControllerComponent with ModelContainerComponent =>
...
}
trait DefaultSubpaneControllerComponent { // Implementation
self: SubpaneViewComponent with ModelContainerComponent =>
...
}
trait SubpaneProvider { // A component which aids in dynamic subpane creation
def newSubpane(): Subpane
}
object SubpaneProvider {
type Subpane = SubpaneControllerComponent with SubpaneViewComponent
}
trait DefaultSubpaneProvider { // Provider component implementation
self: ModelContainerComponent =>
def newSubpane() = new DefaultSubpaneControllerComponent with DefaultSubpaneViewController with ModelContainerComponent {
val model = self.model // Pass global dependency to the dynamic cake
}.asInstanceOf[Subpane]
}
Poi impasto DefaultSubpaneProvider
nella mia torta di livello superiore e iniettare SubpaneProvider
in tutte le componenti che hanno bisogno di creare subpanes.
Il problema in questo approccio è che devo passare manualmente le dipendenze (model
in ModelContainerComponent
) dalla torta di livello superiore alla torta creata dinamicamente. Questo è solo un esempio banale, ma ci possono essere più dipendenze, e anche ci possono essere più tipi di torte create dinamicamente. Tutti richiedono il passaggio manuale delle dipendenze; inoltre, una semplice modifica dell'interfaccia di alcuni componenti può portare a una grande quantità di correzioni in più provider.
C'è un modo più semplice/più pulito per farlo? Come si risolve questo problema all'interno del modello di torta?
Se la risposta non risolve la tua domanda, la cancellerò nuovamente. –
E a proposito di qualcosa come – chemikadze
'tratto ModelContainerComponentProxy estende ModelContainerComponent {def originalModelContainer: ModelContainerComponentProxy; def model = originalModelContainer.model} '- che potrebbe risolvere almeno il problema di passare esplicitamente il contenuto di tutti i componenti. – chemikadze