[JAVA] Résumer l'injection de rubis et de dépendances

Je suis tombé sur un conteneur DI lors du développement avec Laravel, et je pensais que je n'avais jamais utilisé DI en développant avec Rails, donc je vais résumer pourquoi DI n'est pas courant dans Ruby (Rails).

TL;DR ―― Puisque Ruby peut changer dynamiquement la dépendance sur l'instance, DI est fondamentalement inutile. ―― Reportez-vous presque à l'article ci-dessous, donc si vous parlez anglais, veuillez lire cet article. LEGOs, Play-Doh, and Programming

DI DI (Dependency Injection) est une technologie qui élimine la dépendance entre les instances appelée injection de dépendance. Il est pratique pour remplacer des objets fictifs pendant les tests, car vous pouvez injecter des instances dépendantes de l'extérieur. Le framework DI est une technique qui réalise un couplage lâche et une agrégation élevée en laissant le conteneur DI créer et injecter des instances. Certains frameworks DI sont couramment utilisés pour les applications natives (je ne connais pas iOS), prenons donc Java comme exemple.

Java

public class A {
    //L'instance B est générée à l'intérieur de A et le degré de connexion est élevé
    public Client client = new B();
}

interface Client {
    String outputSelf();
}

public class B implements Client {
    @Override 
    public String outputSelf() {
        return "B";
    }
}

public class C implements Client {
    @Override 
    public String outputSelf() {
        return "C";
    }
}

DI résout ce problème, et il en existe plusieurs types, mais en prenant l'injection de constructeur comme exemple, cela ressemble à ce qui suit. A perd la substance de B et devient faiblement couplé.

public class A {
    public Client client;
    public void A(Client client) {
        this.client = client;
    }
}

Cependant, dans ce cas, l'appelant est responsable de la création de l'instance à injecter dans A, et les responsabilités sont réparties, donc lors de l'utilisation du conteneur DI (ex. Dagger2), cela ressemble à ceci. Le conteneur DI est chargé d'injecter la dépendance à l'activité, y compris A.

public class A {
    public Client client;
    @Inject
    public void A(Client client) {
        this.client = client;
    }
}

Ruby Comme expliqué jusqu'ici, DI facilite le remplacement d'objets en le rendant dépendant de l'interface au lieu de la classe concrète (instance). Ensuite, comme dans la conclusion du début, qu'est-ce que cela signifie qu'un mécanisme comme un conteneur DI n'est pas nécessaire dans Ruby? Même si vous souhaitez effectuer une injection, la fonction de langage d'origine de Ruby peut suffisamment réaliser un couplage lâche et une agrégation élevée. Il semble que l'utilisation d'un conteneur DI ne peut qu'ajouter de la complexité.

Comme pour l'exemple Java, si une injection de constructeur est effectuée, ce sera comme suit.

class A 
  def initialize(options={})
    @client_impl = options[:client] || B
  end
  def new_client
    @client_impl.new
  end
end
class B end
class C end

Reflection Une technologie qui lit ou réécrit la structure du programme lui-même lors du processus d'exécution du programme. Dans cet article, il s'agit d'une méthode de réécriture dynamique de l'entité de client, qui est membre de la classe A, de l'extérieur.

Ruby

L'article original indique que Ruby est la langue suivante.

The very Ruby language itself is designed for this: closures, super-simple introspection of objects, runtime modification of existing objects, and the use of modules for extending classes and objects all tend to result in an environment that is simple, malleable, and extensible.

Par conséquent, si vous écrivez dynamiquement comme Ruby,

class A
  def new_client
    client.new
  end
  def client
    B
  end
end

class B end
class C end

Même l'instance créée peut être facilement modifiée.

#La méthode d'instance peut être modifiée dynamiquement
def A.new.client
  C
end

Java La réflexion est également prise en charge en Java, vous pouvez donc remplacer les membres de l'instance comme suit, mais ...

class D {
    public static void main(String args[]){
        try {
            A a_instance = new A();
            Class a = a_instance.getClass();
            Field field = a.getDeclaredField("client");
            System.out.println("before reflection:" + ((Client) field.get(a_instance)).outputSelf());
            field.setAccessible(true);
            field.set(a_instance, new C());
            System.out.println("after reflection:" + ((Client) field.get(a_instance)).outputSelf());

        } catch (Exception e) {}
    }
}

Par rapport au cas de l'injection, il est extrêmement difficile à comprendre et la complexité augmente.

Conclusion

Ruby est plus dynamique que des langages comme Java, et même une fois créé, il est facile de changer et de changer les dépendances. Par conséquent, il semble que l'introduction d'un mécanisme tel qu'un conteneur DI, qui était nécessaire dans un langage statique, ne ferait qu'augmenter la complexité.

Recommended Posts

Résumer l'injection de rubis et de dépendances
Rubis et gemme
[Ruby] Classes et instances
Symboles et rubis destructeur
[Ruby] Big Decimal et DECIMAL
Classes et instances Ruby
Héritage et délégation Ruby
Dagger2 - Injection de dépendance Android
DI: Qu'est-ce que l'injection de dépendance?
Erreurs de syntaxe et contre-mesures Ruby
À propos des hachages et symboles Ruby
Dagger2 - Injection de dépendance Android
DI: Qu'est-ce que l'injection de dépendance?
Résumer l'injection de rubis et de dépendances
Extension Ruby C et volatile
À propos de Ruby, modèle objet
[Ruby] Méthodes singulières et classes singulières
À propos des classes et des instances Ruby
Méthodes et classes Ruby (basiques)
Création de classes et d'instances Ruby
[Ruby] Différence entre obtenir et publier
[Ruby] Différence entre is_a? Et instance_of?
Entrée standard Ruby et diverses méthodes
À propos des guillemets simples et doubles Ruby
[Bases de Ruby] méthode split et méthode to_s
À propos de l'opérateur de produit Ruby (&) et de l'opérateur somme (|)
Ecrire des clés et des valeurs dans Ruby
Mise à niveau de la version du projet Ruby and Rails
À propos de l'héritage orienté objet et du rendement Ruby