73 votes

Comment faites-vous l’injection de dépendance avec le modèle de gâteau sans coder en dur ?

J’ai juste lu et apprécié le gâteau modèle article. Toutefois, à mon avis, une des principales raisons d’utiliser l’injection de dépendance est que vous pouvez faire varier les éléments utilisés par un fichier XML ou les arguments de ligne de commande.

Comment cet aspect de DI est géré avec le modèle de gâteau ? Les exemples que j’ai vu tous impliquent mélangeant traits dans statiquement.

56voto

Dave Griffith Points 12923

Depuis le mélange des caractères se fait de manière statique en Scala, si vous voulez varier les traits mixtes à un objet, de créer différents objets en fonction de certaines conditions.

Prenons un canoniques modèle de gâteau exemple. Vos modules sont définis comme des traits, et votre application est construite comme un simple Objet avec un tas de fonctionnalités mixte dans

val application =
    new Object
extends Communications
   with Parsing
   with Persistence
   with Logging
   with ProductionDataSource
application.startup

Désormais, tous ces modules ont une belle auto-déclarations de type qui définissent leurs inter-dépendances de modules, de sorte que la ligne ne compile si votre tous les inter-dépendances des modules existent, sont uniques, et bien typé. En particulier, le module de Persistance a un auto-type qui dit que tout ce que la mise en œuvre de la Persévérance doit également mettre en œuvre la source de données, un résumé du module de trait. Depuis ProductionDataSource hérite de la source de données, tout est grand, et que l'application de la construction de la ligne de compile.

Mais que faire si vous souhaitez utiliser une autre source de données, en soulignant certains locaux de la base de données à des fins de test? De plus, supposons que vous ne pouvez pas réutiliser ProductionDataSource avec différents paramètres de configuration, chargé de certaines propriétés de fichier. Ce que vous feriez dans ce cas est de définir un nouveau trait TestDataSource qui s'étend de la source de données, et le mélanger à la place. Vous pouvez même le faire de façon dynamique en fonction d'une option de ligne de commande.

val application = if (test)
    new Object
extends Communications
   with Parsing
   with Persistence
   with Logging
   with TestDataSource
else
    new Object
extends Communications
   with Parsing
   with Persistence
   with Logging
   with ProductionDataSource

application.startup

Maintenant, qui ressemble un peu plus verbeux que nous l'aimerions, en particulier si votre application a besoin de faire varier sa construction sur plusieurs axes. Sur le côté positif, vous vous avez seulement un morceau de construction conditionnelle, la logique comme ça dans une application (ou au pire une fois par identifiables composante du cycle de vie), donc au moins la douleur est réduite au minimum et clôturé de le reste de votre logique.

29voto

shellholic Points 3309

Scala est aussi un langage de script. Si votre configuration XML peut être un script Scala. Il est de type sécurisé et n’est pas-un-autre-langue.

Il suffit de regarder au démarrage :

n’est pas tellement différent de :

Vous pouvez toujours utiliser DI, mais vous avez un outil de plus.

5voto

Kevin Wright Points 31665

La réponse courte est que la Scala n'est pas actuellement prise en charge intégrée pour la dynamique mixin.

Je suis en train de travailler sur la autoproxy-plugin pour le soutenir, même s'il est actuellement en attente jusqu'à la version 2.9, lorsque le compilateur aura de nouvelles fonctionnalités le rendant une tâche beaucoup plus facile.

En attendant, le meilleur moyen d'atteindre presque exactement la même fonctionnalité est par la mise en œuvre de votre ajoutées dynamiquement le comportement de l'enveloppe de la classe, puis l'ajout d'une conversion implicite de retour à la enveloppé membre.

3voto

axel22 Points 17400

Jusqu'à ce que le AutoProxy plugin est disponible, un moyen de parvenir à l'effet consiste à utiliser la délégation:

trait Module {
  def foo: Int
}

trait DelegatedModule extends Module {
  var delegate: Module = _
  def foo = delegate.foo
}

class Impl extends Module {
  def foo = 1
}

// later
val composed: Module with ... with ... = new DelegatedModule with ... with ...
composed.delegate = choose() // choose is linear in the number of `Module` implementations

Mais attention, l'inconvénient de cette est que c'est plus détaillé, et vous devez être prudent au sujet de l'ordre d'initialisation si vous utilisez vars à l'intérieur d'un trait. Un autre inconvénient est que si il y a des chemin des types dépendants au sein d' Module - dessus, vous ne serez pas en mesure d'utiliser la délégation qui facilement.

Mais si il y a un grand nombre d'implémentations différentes qui peuvent être modifiées, elle sera probablement vous coûter moins de code que d'énumérer les cas avec toutes les combinaisons possibles.

0voto

sblundy Points 27163

Ascenseur a quelque chose dans ce sens construit en. C’est principalement dans le code de la scala, mais vous avez un contrôle runtime. http://www.assembla.com/wiki/show/liftweb/Dependency_Injection

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X