Cette question est subjective mais j'étais simplement curieux de voir comment la plupart des programmeurs abordent cela. L'exemple ci-dessous est en pseudo-C #, mais cela devrait également s'appliquer à Java, C ++ et à d'autres langages POO.
Quoi qu'il en soit, lors de l'écriture de méthodes d'assistance dans mes classes, j'ai tendance à les déclarer statiques et à ne transmettre que les champs si la méthode d'assistance en a besoin. Par exemple, étant donné le code ci-dessous, je préfère utiliser l’ appel de méthode n ° 2 .
class Foo
{
Bar _bar;
public void DoSomethingWithBar()
{
// Method Call #1.
DoSomethingWithBarImpl();
// Method Call #2.
DoSomethingWithBarImpl(_bar);
}
private void DoSomethingWithBarImpl()
{
_bar.DoSomething();
}
private static void DoSomethingWithBarImpl(Bar bar)
{
bar.DoSomething();
}
}
Mon objectif est que cela indique clairement (du moins à mes yeux) que la méthode d'assistance a un effet secondaire possible sur d'autres objets, même sans lire son implémentation. Je trouve que je peux rapidement maîtriser les méthodes qui utilisent cette pratique et m'aident donc à déboguer des choses.
Ce qui vous préférez faire dans votre propre code et quelles sont vos raisons de le faire?
Réponses:
Cela dépend vraiment. Si les valeurs que vos assistants exploitent sont des primitives, alors les méthodes statiques sont un bon choix, comme l'a souligné Péter.
Si elles sont complexes, puis SOLID applique, plus précisément le S , le I et le D .
Exemple:
Ce serait à propos de votre problème. Vous pouvez créer
makeEveryBodyAsHappyAsPossible
une méthode statique prenant en compte les paramètres nécessaires. Une autre option est:Maintenant,
OurHouse
je n'ai pas besoin de connaître la complexité des règles de distribution des cookies. Il doit seulement maintenant un objet, qui implémente une règle. L'implémentation est abstraite dans un objet dont la seule responsabilité est d'appliquer la règle. Cet objet peut être testé isolément.OurHouse
peut être testé avec un simple simulacre deCookieDistributor
. Et vous pouvez facilement décider de modifier les règles de distribution des cookies.Cependant, veillez à ne pas en faire trop. Par exemple, avoir un système complexe de 30 classes agit comme une implémentation
CookieDistributor
, chaque classe ne remplissant qu'une tâche minuscule, cela n'a pas vraiment de sens. Mon interprétation du SRP est qu’il ne stipule pas seulement que chaque classe ne peut avoir qu’une responsabilité, mais qu’une seule responsabilité doit être assumée par une classe.Dans le cas de primitives ou d'objets que vous utilisez comme des primitives (par exemple, des objets représentant des points dans l'espace, des matrices ou autre), les classes d'assistance statique ont beaucoup de sens. Si vous avez le choix, et que cela a vraiment du sens, vous pourriez alors envisager d'ajouter une méthode à la classe représentant les données, par exemple, il est judicieux pour a
Point
d'avoir uneadd
méthode. Encore une fois, n'en faites pas trop.Donc, en fonction de votre problème, il y a différentes façons de s'y prendre.
la source
Décrire des méthodes de classes d'utilitaires est un idiome bien connu
static
, de telles classes n'ont donc jamais besoin d'être instanciées. Suivre cet idiome rend votre code plus facile à comprendre, ce qui est une bonne chose.Il existe cependant une limite sérieuse à cette approche: de telles méthodes / classes ne peuvent pas être facilement moquées (bien que, autant que je sache, du moins pour C #, il existe des frameworks moqueurs qui peuvent y parvenir, mais ils ne sont pas banals et au moins certains sont commercial). Ainsi, si une méthode auxiliaire a une dépendance externe (par exemple, une base de données) qui la rend difficile, ainsi que ses appelants, à effectuer des tests unitaires, il est préférable de la déclarer non statique . Cela permet l'injection de dépendance, facilitant ainsi le test unitaire des appelants de la méthode.
Mise à jour
Clarification: ce qui précède parle de classes d’utilitaires, qui ne contiennent que des méthodes d’aide de bas niveau et (généralement) aucun état. Les méthodes d'assistance à l'intérieur de classes non-utilitaires avec état sont un problème différent; excuses pour avoir mal interprété le PO.
Dans ce cas, je sens une odeur de code: une méthode de classe A qui fonctionne principalement sur une instance de classe B peut en fait occuper une meilleure place en classe B. Mais si je décide de le conserver où il se trouve, je préfère l’option 1, comme il est plus simple et plus facile à lire.
la source
Je préfère # 1 (
this->DoSomethingWithBarImpl();
), à moins bien sûr que la méthode d'assistance n'ait pas besoin d'accéder aux données / implémentations de l'instancestatic t_image OpenDefaultImage()
.interface publique et mise en œuvre privée et les membres sont séparés. les programmes seraient beaucoup plus difficiles à lire si je optais pour # 2. avec # 1, j'ai toujours les membres et l'instance disponibles. comparé à de nombreuses implémentations basées sur OO, j’ai tendance à utiliser beaucoup d’encapsulation et très peu de membres par classe. en ce qui concerne les effets secondaires - je suis d'accord avec cela, il y a souvent une validation d'état qui étend les dépendances (par exemple, des arguments à passer).
N ° 1 est beaucoup plus simple à lire, à maintenir et a de bonnes caractéristiques de performance. bien sûr, il y aura des cas où vous pourrez partager une implémentation:
Si # 2 était une bonne solution commune (par exemple la solution par défaut) dans une base de code, je serais préoccupé par la structure de la conception: les classes en font-elles trop? n'y a-t-il pas suffisamment d'encapsulation ou de réutilisation? le niveau d'abstraction est-il suffisamment élevé?
enfin, le n ° 2 semble redondant si vous utilisez des langages OO où la mutation est prise en charge (par exemple, une
const
méthode).la source