Status:
réponses de Fendy et de Glen Best sont également acceptables et honorées par moi, mais comme il est possible d’accepter une récompense et d’obtenir une prime, je choisis la réponse de Fendy.
Scenario:
Si du code doit être réutilisé plusieurs fois dans de nombreuses classes (rarement avec des modifications mineures des parameters, ce qui est évident) et des threads simultanés, quelle approche adopter?
Le code qui doit être réutilisé peut être une chose saine (en prenant en compte le contexte statique et non statique et les techniques de création de méthodes). Ce peut être un algorithme, une méthode DB qui connecte, exploite, ferme. N’importe quoi.
Faites des classes comme MyMethods.class
et mettez toutes ces méthodes dedans .
1.a. Rendre les méthodes static
et appeler (par toutes les classes et tous les threads simultanés) directement en tant que MyMethods.someMethod();
1.b. Rendre les méthodes non-static
et au moment de les appeler, instantiate
la classe entière par MyMethods mm = MyMethods(); mm.someMethod();
MyMethods mm = MyMethods(); mm.someMethod();
Utilisez le modèle de stratégie indiqué à l’ adresse https://en.wikipedia.org/wiki/Strategy_pattern (code joint ici avec).
Utilisez l’ dependency injection indiquée à l’ adresse https://en.wikipedia.org/wiki/Dependency_injection#Java.
Problems:
Certaines personnes diraient que le test unitaire http://en.wikipedia.org/wiki/Unit_testing ne sera pas possible avec cette approche, ce qui rendra plus difficile l’échange de cette dernière. si vous voulez tester votre classe et utiliser une version simulée de la dépendance
1.a. Y aura-t-il des problèmes avec des appels simultanés ou des classes multiples? spécialement dans JDBC static methods
pour un exemple?
1.b. Je pense que cela ferait trop de mémoire car une classe entière serait instanticated
plusieurs fois pour appeler une ou deux méthodes.
C’est bien au-dessus de ma tête, expliquez cela et / ou les avantages / inconvénients
Je ne veux pas utiliser un cadre dans le contexte de cette question. C’est clair, expliquez-le et, le cas échéant, avec ses avantages / inconvénients.
En attente de toute autre stratégie ou recommandation, le cas échéant.
Request:
Veuillez ne répondre que si vous êtes expérimenté et si vous connaissez bien les implications et pouvez, avec votre réponse, m’aider et aider la communauté dans son ensemble!
Code:
/** The classes that implement a concrete strategy should implement this. * The Context class uses this to call the concrete strategy. */ interface Strategy { int execute(int a, int b); } /** Implements the algorithm using the strategy interface */ class Add implements Strategy { public int execute(int a, int b) { System.out.println("Called Add's execute()"); return a + b; // Do an addition with a and b } } class Subtract implements Strategy { public int execute(int a, int b) { System.out.println("Called Subtract's execute()"); return a - b; // Do a subtraction with a and b } } class Multiply implements Strategy { public int execute(int a, int b) { System.out.println("Called Multiply's execute()"); return a * b; // Do a multiplication with a and b } } // Configured with a ConcreteStrategy object and maintains // a reference to a Strategy object class Context { private Strategy strategy; public Context(Strategy strategy) { this.strategy = strategy; } public int executeStrategy(int a, int b) { return this.strategy.execute(a, b); } } /** Tests the pattern */ class StrategyExample { public static void main(Ssortingng[] args) { Context context; // Three contexts following different strategies context = new Context(new Add()); int resultA = context.executeStrategy(3,4); context = new Context(new Subtract()); int resultB = context.executeStrategy(3,4); context = new Context(new Multiply()); int resultC = context.executeStrategy(3,4); System.out.println("Result A : " + resultA ); System.out.println("Result B : " + resultB ); System.out.println("Result C : " + resultC ); } }
Votre question a en fait deux sens.
qui doit être réutilisé plusieurs fois dans de nombreuses classes
Il peut s’agir d’un contexte de modèle de conception (composant réutilisable) ou de coût en mémoire (instanciation de classe). Parler de deux outlook différentes:
Cette section ne couvre en réalité que 2 types d’instanciation.
Le premier est statique (ou instanciation DI dans la racine de la composition)
Non statique
En bref, le coût statique sera élevé si la classe est nombreuse et non statique si la demande est élevée (boucle interne, par exemple). Mais cela ne devrait pas alourdir votre application. La plupart des opérations dans java / csharp sont des objects créés.
1 – méga code monolithique (une classe de dieu capable de presque tout faire)
Avantages:
Désavantages:
Modèle 1a / classe statique / singleton
Avantages:
Désavantages:
Quelques points sur la classe statique: voir cette question
2 modèle de stratégie
En fait, cela a la même conception avec 3 ou la composition over inheritance
.
3 dependency injection
Avantages:
Must be stateless
. Il est plus facile de déboguer et de tester l’unité si la classe est sans état Le désavantage:
Je pense que les États jouent des règles importantes dans la conception de votre application. Les développeurs essaient généralement d’éviter d’avoir des états dans le code de la logique métier, tels que:
// get data if(request.IsDraft){ // step 1 // step 2 } else{ // step 1 // step 3 }
Les développeurs ont tendance à mettre la logique dans une autre classe stateless
, ou du moins des méthodes telles que:
// get data if(request.IsDraft){ draftRequestHandler.Modify(request); } else{ publishedRequestHandler.Modify(request); }
Il offrira une meilleure lisibilité et facilitera les modifications et les tests unitaires. Il existe également un modèle d’ state pattern or hierarchial state machine pattern
conception state pattern or hierarchial state machine pattern
, en particulier pour traiter certains cas de ce type.
IMHO, ce principe est le plus avantageux s’il est suivi. Les avantages sont:
Cette conception ne garantit pas que votre code est exempt de bugs. Contre le coût de temps en phase de conception et l’effort de superposition, il présente les avantages suivants:
Service Locator Anti Pattern
Utilisation de Decorator pour des problèmes transversaux
Mes 2 centimes:
L’avantage d’utiliser l’interface (s’applique également à la composition de l’inheritance)
Faire du design descendant / design DI
Ces conceptions et stratégies ne sont pas la clé qui déterminera la structure de votre application. C’est toujours l’architecte qui le déterminera. Je préfère suivre certains principes tels que SOLID, KISS et GRASP, plutôt que de décider quelle est la meilleure structure. Il est dit que l’dependency injection suit la plupart de ces principes, mais une trop grande abstraction et une conception de composants incorrecte entraîneront le même résultat avec l’utilisation abusive du modèle de singleton.
1.a. Rendre les méthodes statiques et appeler (par toutes les classes et tous les threads simultanés) directement en tant que MyMethods.someMethod ();
1.b. Rendre les méthodes non statiques et au moment de les appeler, instancier la classe entière par MyMethods mm = MyMethods (); mm.someMethod ();
Le choix entre ces deux dépend de la fonctionnalité de MyMethods.class
. Si MyMethods
est censé être sans état, c’est une bonne approche pour utiliser static
méthodes static
. Sinon, si un appel de méthode dépend d’un autre et que MyMethods
a des états (c’est-à-dire des champs non finaux), utilisez la deuxième option.
Utilisez le modèle de stratégie indiqué à l’ adresse https://en.wikipedia.org/wiki/Strategy_pattern (code joint ici avec).
Utilisez ce modèle si MyMethods
doit être étendu avec différentes classes à des fins différentes et si vous sélectionnez le code à exécuter en fonction de votre contexte. Comme le dit le wiki , si vous ne connaissez pas l’algorithme à utiliser avant l’exécution (cela dépend de certaines conditions), c’est la voie à suivre. Selon vos spécifications de MyMethods
vous n’avez pas de tels problèmes.
Utilisez l’dependency injection indiquée à l’ adresse https://en.wikipedia.org/wiki/Dependency_injection#Java.
Même réponse que ci-dessus. La chose avec l’ dependency injection est en inversion de contrôle . Une classe qui utilise MyMethods
ne connaît pas la mise en œuvre réelle de MyMethods
, mais l’injection de la mise en œuvre réelle est déléguée à une autorité de niveau supérieur. Il abstrait les dépendances externes du contexte dans lequel il va être utilisé. Encore une fois, si MyMethods
doit être sans état et constant (il n’est pas prévu de changer, et le comportement des méthodes dans la classe ne dépend pas du contexte dans lequel elles sont utilisées), vous n’avez pas besoin de ces modèles, car cela signifierait simplement une ingénierie excessive.
Je conclurais que vous devriez utiliser un modèle Strategy ou DI si la logique de MyMethods
dépend du contexte dans lequel ils sont exécutés. Si ceci est constant (par exemple, la classe Math
de Java ne se soucie pas de savoir qui ou dans quel contexte quelqu’un appelle sqrt()
, max()
ou pow()
), alors les méthodes statiques sont la solution.
Concernant les problèmes:
Les problèmes que vous avez indiqués ne sont pas présents lorsque vous utilisez MyMethods
avec static
méthodes static
. Vous devrez vérifier si vos méthodes renvoient des valeurs correctes pour des arguments particuliers, et c’est tout. Je ne pense pas qu’il y aurait beaucoup plus de difficulté à tester la mise en œuvre réelle de Strategy
in Strategy ou la mise en œuvre d’interface injectée via l’ dependency injection . Ce qui pourrait être plus difficile, c’est de tester les classes qui utilisent la stratégie, car il n’est parfois pas facile de recréer le contexte dans lequel une stratégie particulière sera exécutée, car cela dépend souvent de l’entrée de l’utilisateur, mais ce n’est certainement pas impossible. L’dependency injection est, en ce qui me concerne, un excellent moyen de test car vous pouvez séparer l’unité sous test de la dépendance que vous pouvez facilement simuler.
La question principale: la réutilisation du code
Si du code doit être réutilisé plusieurs fois dans de nombreuses classes (rarement avec des modifications mineures des parameters, ce qui est évident) et des threads simultanés, quelle approche adopter?
Parce que vous n’envisagez pas de couper-coller, je pense que vous voulez dire:
… réutilisé plusieurs fois par plusieurs classes …
Ce que vous demandez n’est rien de spécial ou de spécifique. Il est courant que le code soit réutilisé, soit dans une seule application, soit dans plusieurs applications. La réponse commune: utilisez une conception / programmation orientée object . Mettez le code dans une classe, créez un object en tant qu’instance, appelez l’object …
1a. Réutilisation via des méthodes statiques:
Rendre les méthodes statiques et appeler (par toutes les classes et tous les threads simultanés) directement en tant que MyMethods.someMethod ()
1b. Réutilisation via des méthodes non statiques, avec instanciation d’object:
Rendre les méthodes non statiques et au moment de les appeler, instancier la classe entière par MyMethods mm = MyMethods (); mm.someMethod ();
Utiliser un modèle de stratégie
Le modèle de stratégie peut être une bonne pratique. Mais cela a peu à voir avec votre question globale. Le modèle de stratégie est utilisé pour une raison spécifique – pour permuter l’implémentation de la logique algorithme / traitement “à la volée” sans impacter l’appelant.
Utiliser l’dependency injection
L’dependency injection est utilisée pour les raisons suivantes:
Cela peut être une très bonne pratique, si elle est utilisée correctement. Dans votre cas, cela ne pourrait jamais s’appliquer que dans le cadre de l’option 1b. L’dependency injection concerne l’instanciation et la provision d’objects dans des variables.
Problèmes:
Certaines personnes diraient que le test unitaire ne sera pas possible
1a. Voir au dessus
1b. Chargement de la mémoire
Je pense que cela ferait trop de mémoire car une classe entière serait instanciée plusieurs fois pour appeler une ou deux méthodes.
Un petit problème. Selon les données dans chaque instance d’object (les variables d’instance), chaque instance d’object peut être aussi petite qu’une douzaine d’octets ou aussi grande que des mégaoctets – mais est généralement inclinée vers le bas (souvent <1 Ko). La consommation de mémoire du code de classe n’est pas répliquée à chaque fois que la classe est instanciée.
Bien sûr, il est judicieux de minimiser le volume d’objects, en fonction de vos besoins. Ne créez pas d’instance si vous en avez déjà une utilisable. Créez moins d’instances d’object et partagez-les sur votre application, en les transmettant aux méthodes de constructeur et aux méthodes de définition. L’dependency injections est un bon moyen de partager des instances d’object “automatiquement” sans les transmettre aux constructeurs / setters.
Voir au dessus
Voir au dessus