J'ai récemment rencontré la situation suivante.
class A{
public:
void calculate(T inputs);
}
Premièrement, A
représente un objet dans le monde physique, ce qui est un argument fort pour ne pas diviser la classe. Maintenant, cela calculate()
s'avère être une fonction assez longue et compliquée. J'en perçois trois structures possibles:
- l'écrire comme un mur de texte - avantages - toutes les informations sont en un seul endroit
- écrire des
private
fonctions utilitaires dans la classe et les utiliser danscalculate
le corps de - inconvénients - le reste de la classe ne sait pas / ne prend pas soin / ne comprend pas ces méthodes écrivez de
calculate
la manière suivante:void A::calculate(T inputs){ auto lambda1 = () [] {}; auto lambda2 = () [] {}; auto lambda3 = () [] {}; lambda1(inputs.first_logical_chunk); lambda2(inputs.second_logical_chunk); lambda3(inputs.third_logical_chunk); }
Cela peut-il être considéré comme une bonne ou une mauvaise pratique? Cette approche révèle-t-elle des problèmes? Dans l'ensemble, dois-je considérer cela comme une bonne approche lorsque je suis à nouveau confronté à la même situation?
ÉDITER:
class A{
...
public:
// Reconfiguration of the algorithm.
void set_colour(double colour);
void set_density(double density);
void set_predelay(unsigned long microseconds);
void set_reverb_time(double reverb_time, double room_size);
void set_drywet(double left, double right);
void set_room_size(double value);;
private:
// Sub-model objects.
...
}
Toutes ces méthodes:
- obtenir une valeur
- calculer d'autres valeurs, sans utiliser l'état
- appeler certains des "objets de sous-modèle" pour changer leur état.
Il s'avère que, sauf que set_room_size()
ces méthodes transmettent simplement la valeur demandée aux sous-objets. set_room_size()
, d'autre part, fait un couple d'écrans de formules obscures, puis (2) fait un demi-écran d'appel de sous-objets setters pour appliquer les différents résultats obtenus. Par conséquent, j'ai séparé la fonction en deux lambdas et je les appelle à la fin de la fonction. Si j'avais pu le diviser en morceaux plus logiques, j'aurais isolé plus de lambdas.
Quoi qu'il en soit, l'objectif de la question actuelle est de déterminer si cette façon de penser doit persister, ou au mieux ne pas ajouter de valeur (lisibilité, maintenabilité, capacité de débogage, etc.).
Firstly, A represents an object in the physical world, which is a strong argument for not splitting the class up.
A
Représente sûrement des données sur un objet qui pourrait exister dans le monde physique. Vous pouvez avoir une instance deA
sans l'objet réel et un objet réel sans une instance deA
, donc les traiter comme si elles étaient une seule et même chose n'a pas de sens.calculate()
ne connaît ces sous-fonctions.A
, cela va un peu à l'extrême.A
représente un objet dans le monde physique, ce qui est un argument solide pour ne pas diviser la classe." On m'a malheureusement dit cela lorsque j'ai commencé à programmer. Il m'a fallu des années pour réaliser que c'est un tas de hockey sur cheval. C'est une raison terrible de grouper des choses. Je ne peux pas expliquer quelles sont les bonnes raisons de grouper les choses (au moins à ma satisfaction), mais celle-là est celle que vous devriez rejeter dès maintenant. En fin de compte, tout le "bon code" est qu'il fonctionne correctement, qu'il est relativement facile à comprendre et qu'il est relativement facile de changer (c'est-à-dire que les changements n'ont pas d'effets secondaires étranges).Réponses:
Non, ce n'est généralement pas un bon schéma
Ce que vous faites est de diviser une fonction en fonctions plus petites à l'aide de lambda. Cependant, il existe un bien meilleur outil pour décomposer les fonctions: les fonctions.
Les lambdas fonctionnent, comme vous l'avez vu, mais ils signifient beaucoup beaucoup beaucoup plus que la simple décomposition d'une fonction en bits locaux. Les Lambdas font:
À l'instant où vous introduisez des lambdas dans le mélange, le prochain développeur à regarder le code doit immédiatement charger mentalement toutes ces règles afin de voir comment fonctionne votre code. Ils ne savent pas que vous n'utiliserez pas toutes ces fonctionnalités. C'est très cher par rapport aux alternatives.
C'est comme utiliser une pelle rétrocaveuse pour faire votre jardinage. Vous savez que vous ne l'utilisez que pour creuser de petits trous pour les fleurs de cette année, mais les voisins deviendront nerveux.
Considérez que tout ce que vous faites est de regrouper visuellement votre code source. Le compilateur ne se soucie pas vraiment que vous curiez les choses avec des lambdas. En fait, je m'attendrais à ce que l'optimiseur annule immédiatement tout ce que vous venez de faire lors de la compilation. Vous vous adressez uniquement au lecteur suivant (merci de le faire, même si nous ne sommes pas d'accord sur la méthodologie! Le code est lu beaucoup plus souvent qu'il n'est écrit!). Tout ce que vous faites, c'est regrouper des fonctionnalités.
// ------------------
entre chaque partie.EDIT: En voyant votre édition avec un exemple de code, je penche pour que la notation des commentaires soit la plus propre, avec des crochets pour appliquer les limites suggérées par les commentaires. Cependant, si l'une des fonctionnalités était réutilisable dans d'autres fonctions, je recommanderais d'utiliser des fonctions à la place
la source
count++
)calculate()
en{}
blocs et en déclarant des données partagées au niveau de lacalculate()
portée. Je pensais qu'en voyant que les lambdas ne capturaient pas, un lecteur ne serait pas encombré par le pouvoir des lambdas.lambda
soit injuste ou que vous obligiez grossièrement les gens à suivre la dénotation stricte n'est pas une question facile à répondre. En fait, il peut être tout à fait acceptable pour vous d'utiliser delambda
cette façon dans votre entreprise, et totalement inacceptable dans ma société, et ni l'un ni l'autre ne doit se tromper!lambda
, comme lafor_each
fonction. Par conséquent, lorsque je vois unlambda
qui ne correspond pas à l'un de ces cas de panne faciles à repérer, la première hypothèse à laquelle j'arrive est qu'il sera probablement utilisé pour la programmation fonctionnelle, car il n'était pas nécessaire autrement. Pour de nombreux développeurs, la programmation fonctionnelle est un état d'esprit complètement différent de la programmation procédurale ou OO.Je pense que vous avez fait une mauvaise hypothèse:
Je suis en désaccord avec cela. Par exemple, si j'avais une classe qui représente une voiture, je voudrais certainement la diviser, car je veux sûrement une classe plus petite pour représenter les pneus.
Vous devez diviser cette fonction en petites fonctions privées. Si elle semble vraiment séparée de l'autre partie de la classe, cela peut être un signe que la classe doit être séparée. Bien sûr, c'est difficile à dire sans un exemple explicite.
Je ne vois pas vraiment l'avantage d'utiliser les fonctions lambda dans ce cas, car cela ne rend pas vraiment le code plus propre. Ils ont été créés pour faciliter la programmation de style fonctionnel, mais ce n'est pas ça.
Ce que vous avez écrit ressemble un peu aux objets de fonction imbriqués de style Javascript. Ce qui est encore une fois le signe qu'ils sont étroitement liés. Etes-vous sûr que vous ne devriez pas faire une classe séparée pour eux?
Pour résumer, je ne pense pas que ce soit un bon schéma.
MISE À JOUR
Si vous ne voyez aucun moyen d'encapsuler cette fonctionnalité dans une classe significative, vous pouvez créer des fonctions d'assistance à portée de fichier, qui ne sont pas membres de votre classe. C'est du C ++ après tout, la conception OO n'est pas un must.
la source
A
(peut-être même foncteur avec toutes les autres méthodes privées)? Classe déclarée et définie à l'intérieurcalculate()
(cela ressemble beaucoup à mon exemple lambda). À titre de clarification,calculate()
fait partie d'une famille de méthodes (calculate_1(), calculate_2()
etc.) dont toutes sont simples, celle-ci est juste 2 écrans de formules.calculate()
tellement plus long que toutes les autres méthodes?