Question

Contexte rapide: je programme en PHP. Je dispose d’un modèle de domaine avec une couche d’accès aux données (classes DAO) distincte, chargée de récupérer les données de la base de données et de créer les classes de domaine.

Supposons que j'ai une classe DAO responsable de la création des objets groupe et groupList . Vous pouvez imaginer les groupes en tant que composants d’un réseau social; bien que peu importe ce qu’ils sont pour cette question.

Je dois pouvoir demander au DAO de me créer divers objets groupList en fonction de différents critères:

  • les derniers groupes ajoutés
  • les groupes les plus populaires
  • groupes identifiés comme "en vedette" par un administrateur
  • groupes étiquetés avec une certaine balise
  • groupes correspondant à un certain mot clé
  • groupes dans une certaine catégorie
  • groupes créés par une certaine personne
  • groupes créés un certain jour

Certaines de ces choses dont je n’ai pas réellement besoin pour le moment, mais je peux imaginer que j’en aurai besoin avant la fin du projet. Maintenant, j'ai commencé avec une méthode simple et agréable: createList . Cela a très bien fonctionné. Vous pouvez considérer le pseudo-code comme suit:

find out how many groups
create SQL query to fetch group details
loop through results
{
   create group object
   add to group list object
}

Au fur et à mesure que mon application progressait, j'ai ensuite créé une nouvelle méthode createFeaturedList . Cela a très bien fonctionné. En réalité, il ressemblait beaucoup à createList , avec une requête légèrement différente. Une bonne partie du reste des ~ 150 lignes de code était identique.

Alors ... Que dois-je faire pour tous les cas légèrement différents dont j'ai besoin? La plupart du temps, je souhaite simplement filtrer et trier la liste en fonction de certains critères. La question est la suivante: devrais-je:

a) créez de nombreuses méthodes de création ciblées telles que:

  • createList ()
  • createCategoryList (categoryObject)
  • createUsersList (userObject)
  • createTagList (balise)
  • createPopularList ()

ou

b) créez une seule méthode BIG pouvant tout faire:  - createList (searchString, orderBy, filterByCategoryObject = null, filterByUserObject = null)

J'aime assez l'idée de (a) car mon interface DAO est plus simple et nécessite moins de modifications (par exemple, l'ajout d'un autre paramètre lorsque je dois soudainement passer une date à comparer avec ) La difficulté vient quand vous avez des choses comme des mots-clés de recherche que vous voulez pouvoir combiner avec d’autres paramètres; Par exemple: liste de catégories recherchée, liste populaire recherchée, liste de balises recherchées, etc ... (a) est un peu ce que j'ai commencé avec.

J'ai eu un flirt avec le refactoring sur (b) mais je peux voir ma méthode devenir très grande et très complexe assez rapidement, beaucoup de "si" et de "sélectionner" pour traiter les différents cas où la construction du SQL, et beaucoup de paramètres qui sont introduits dans la méthode. Mais au moins, tout est au même endroit. Et vous pouvez combiner des choses; Par exemple: les groupes d'un utilisateur, étiquetés avec blah, les mots clés correspondants blah.

Était-ce utile?

La solution

Vous pouvez créer une méthode privée à laquelle toutes les méthodes publiques font appel. IE

private function _createList ( searchString, orderBy, ... )
{
    ...
}

public function createList()
{
    return $this->_createList('...', 'id');
}

public function createCategoryList()
{
    return $this->_createList('...', 'category_id');
}

Ainsi, si votre fonction _createList doit être modifiée ultérieurement, il vous suffit de refactoriser les méthodes publiques de ce DAO plutôt que de toutes les classes qui l'utilisent.

Autres conseils

Je ne pense pas que ce soit strictement un cas ou une situation. L'option a est une belle interface utilisable par votre DAO, donc vous devriez la garder. Pour moi, l'option b ressemble vraiment à la logique de la mise en œuvre. Donc, si la méthode BIG convient à vos besoins, je vous conseillerais de l’utiliser pour exécuter la logique de traitement réelle tout en exposant l’interface comme dans l’option a.

Cela dit, si la méthode BIG devient trop compliquée et compliquée et que la réutilisation du code augmente réellement la complexité de votre code et diminue la maintenabilité de l'application, vous voudrez peut-être refactoriser pour conserver des instructions SQL distinctes pour chaque méthode d'interface, mais faire exécuter la méthode d'assistance. la logique commune d'analyse des résultats.

La méthode big de l'option B garantit quasiment toute réduction de la réutilisation du code, ainsi qu'une augmentation de la complexité et du temps de maintenance.

Personnellement, (et selon Code Complete), les méthodes devraient faire une chose et le faire bien et ne pas essayer de tout fourrer dedans. Évitez de devoir refactoriser à l'avenir et faites-le intelligemment la première fois.

Principes de base de la programmation: il est recommandé de décomposer vos codes en sections ou en fonctions.

Je vais choisir l'option (a); Vous devrez maintenir et déboguer le code. Et quand vous avez un bogue, vous serez très heureux d'avoir divisé votre code en différentes méthodes.

De plus, écrire le nom de la méthode vous aide à comprendre ce que vous faites.

comparez ceci:

Option (a)

$obj->AddNewList( /* params */ );
$obj->UpdateList( /* params */ );

et ceci:

Option (b)

$obj->parse( /* first set of params */ );
$obj->parse( /* second set of params */ );

Cela permet de gagner du temps en lisant de gauche à droite les humains. C’est pourquoi les noms de fonctions et de méthodes se trouvent toujours à gauche.

Si les performances ne constituent pas un problème majeur ou si les groupes changent suffisamment lentement pour que la mise en cache des requêtes soit utile, vous pouvez écrire des fonctions de filtrage et les transmettre. Si vous parcourez des groupes en boucle et disposez d'un tableau optionnel de filtrage méthodes que votre boucle deviendrait:

for(group in group) {
    cont = true
    for(f in functions) {
        if ! f(group) {cont = false; continue;}
    }
    if(cont) Continue
    add group to list
}

Cela vous permettrait de modifier les paramètres de filtrage sans modifier la boucle, mais simplement d'écrire ou de modifier une fonction.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top