Question

J'ai un gestionnaire d'événements sur une classe de limite qui gère un mécanisme de persistance pour une transaction générique donnée:

void MyBoundaryClass::MyEventHandler(...)
{
  //retrieve stuff from the UI
  //...
  //declare and initialize trasaction to persist
  SimpleTransaction myTransaction(.../*pass down stuff*/);
  //do some other checks
  //...
  //declare transaction persistor
  TransactionPersistor myPersistor(myTransaction, .../*pass down connection to DB and other stuff*/);
  //persist transaction
  try
  {
    myPersistor.Persist();
  }
  catch(...)
  {
    //handle errors
  }
}

Serait-il préférable d'avoir une sorte de TransactionManager pour envelopper les objets SimpleTransaction et TransactionPErsistor?

Existe-t-il une règle utile permettant de comprendre si j'ai besoin d'un niveau d'encapsulation supplémentaire?

Pour le moment, la règle générale que je suis est "si la méthode devient trop grosse, faites quelque chose à ce sujet". Il est parfois difficile de trouver le bon équilibre entre la procédure et l’objet orienté objet lorsqu’il s’agit de gestionnaires d’événements Limite.

Un avis?

A bientôt

Était-ce utile?

La solution

Considérant que:

  • le concept d'encapsulation concerne la définition d'un conteneur, et
  • la conception orientée objet est basée sur le concept de transmission de message (invocation de méthodes)

Je dirais que l'API est un bon indicateur de la pertinence d'une nouvelle encapsulation de haut niveau (c'est-à-dire la définition d'un nouvel objet)

Si les services (c'est-à-dire l'API) proposés par ce nouvel objet sont cohérents et sont mieux exposés au reste du programme lorsqu'ils sont regroupés dans un objet spécial, utilisez-les à l'aide d'un nouvel objet.

Dans le cas contraire, il est probable que vous en ayez trop.

Etant donné que vous exposez une API public en créant un nouvel objet, la notion de test peut être plus facile à réaliser dans ce nouvel objet ( et quelques autres mock objets), plutôt que de créer plusieurs objets hérités afin de tester ces mêmes opérations.

Dans votre cas, si vous souhaitez tester la transaction, vous devez réellement tester MyEventHandler de MyBoundaryClass, afin de récupérer les données de l'interface utilisateur.

Mais si vous définissez TransactionManager, cela vous donne la possibilité de réduire le couplage des différents niveaux d'architecture (interface graphique par rapport aux données) présentes dans MyBoundaryClass et d'exporter la gestion des données dans une classe dédiée. < br> Ensuite, vous pouvez tester la persistance des données dans un scénario de test indépendant, en vous concentrant particulièrement sur les valeurs limites, les défaillances de base de données, les conditions non nominales, etc.

.

Le scénario de test peut vous aider à affiner la cohésion (excellent point mentionné par Daok ) de vos différents objets. Si vos tests sont simples et cohérents, il est probable que vos objets possèdent une frontière de service bien définie.

Puisqu'on peut soutenir que le le couplage et la cohésion sont deux pierres angulaires de la programmation OO , la cohésion d'une nouvelle classe telle que TransactionManager peut être évaluée en fonction de l'ensemble des actions qu'elle effectuera.

  

Cohésif signifie qu'une classe donnée effectue un ensemble d'actions étroitement liées. D'autre part, un manque de cohésion signifie qu'une classe effectue plusieurs tâches non liées. [...] le logiciel d'application finira par devenir ingérable, de plus en plus de comportements se dispersant et se retrouvant au mauvais endroit.

Si vous regroupez dans TransactionManager des comportements mis en œuvre de différentes manières dans votre compte, cela devrait aller, à condition que son API publique représente des étapes claires de ce qu'une transaction implique et non pas des "informations relatives à une transaction". comme diverses fonctions utilitaires. Un nom en soi ne suffit pas pour juger de la cohésion d'une classe. La combinaison du nom et de son API publique est nécessaire.

Par exemple, un aspect intéressant d’un gestionnaire TransactionManager serait d’encapsuler complètement la notion de transaction, ce qui:

  • deviendrait pratiquement inconnu du reste du système et réduirait le couplage entre les autres classes et 'Transaction'
  • renforcez la cohésion de TransactionManager en centrant son API autour des étapes de transaction (comme initTransaction (), persistTransaction (), ...), en évitant tout getter ou setter pour toute instance de Transaction.

Autres conseils

En vous appuyant sur la suggestion de VonC, tenez compte des directives suivantes:

  • Si vous prévoyez d'appeler les mêmes fonctions ailleurs, de la même manière, il est raisonnable de les encapsuler dans un nouvel objet.

  • Si une fonction (ou un objet) fournit un ensemble d’installations utiles individuellement, il est raisonnable de la reformuler en composants plus petits.

Le point de VonC sur l’API est un excellent test décisif: créez des interfaces efficaces, et les objets deviennent souvent évidents.

Le niveau d'encapsulation doit être lié ??directement à la cohésion de votre objet. Votre objet doit effectuer une seule tâche ou doit être divisé en plusieurs classes et encapsuler tous ses comportements et propriétés.

Une règle de base est le moment de tester votre objet. Si vous effectuez des tests unitaires et que vous réalisez que vous testez plusieurs choses différentes (pas dans la même action de domaine) que celles que vous pourriez essayer de diviser.

En ce qui concerne votre cas , j'encapsulerais votre idée de "TransactionManager". Ainsi, le " TransactionManager " gérera le fonctionnement de la transaction et non pas "MyBoundaryClass".

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