2010-11-23 32 views
1

Un collègue de travail de la mine a tendance à concevoir des classes comme:Où pourrais-je trouver un argument concis et bien écrit contre cet anti-pattern d'initialisation, et éventuellement d'autres?

class ImportantClass 
{ 
    public SomeClass ImportantField; 
    public SomeOtherClass OtherImportantField; 
    // etc. 
} 

Il va écrire aucun constructeur. Ensuite, partout où il instancie ce type son code ressemblera à ceci:

ImportantClass x; 

try 
{ 
    // This is problematic enough to begin with, as every field (which is public) 
    // is set manually, which causes code duplication wherever this type is 
    // instantiated as well as maintenance problems in the event new fields are 
    // introduced or internal implementation is changed. 
    x = new ImportantClass(); 
    x.ImportantField = new SomeClass(); 
    x.OtherImportantField = new SomeOtherClass(); 
} 
catch (Exception ex) 
{ 
    // ...what's even worse: now x can easily be in a totally invalid state, 
    // with some fields initialized and some not. 
    HandleAnyException(ex); 
} 

Il est évident que ce qui précède est un exemple simplificatrice (et exagérée); mais je pense que vous avez compris. Je ne poste pas cela pour critiquer mon collègue; Au contraire, je veux lui faire part des nombreux problèmes rencontrés dans le développement de classes comme celle-ci et le diriger dans la bonne direction. Personnellement, je pense que cette conception, bien que médiocre, est quelque chose qui est facilement "réparé".

Ma principale préoccupation est que si je veux le convaincre, il sera important pour moi d'avoir un argument qui est fort (bien soutenu), facile à comprendre, et concis (il ne va pas vouloir lire un courriel de 2 pages lui disant pourquoi je pense que son code doit changer).

Y a-t-il de bonnes ressources qui fournissent des arguments si bien conçus, abordant les inconvénients de ceci et peut-être d'autres anti-modèles mal conçus? Quelque chose comme un recueil des «erreurs courantes de conception de logiciels» serait extrêmement utile, s'il existe.

Remarque: Je me rends compte que tout simplement parler à ce sujet est la façon la plus directe et probablement perturber le moins possible de donner des conseils; Je pense simplement, ce serait bien d'avoir aussi cette ressource que je peux citer comme référence, encore une fois, si une telle ressource existe.

+1

Wow. Ils le paient pour écrire des trucs comme ça? –

Répondre

2

Cela enfreint les principes de responsabilité. Si ImportantClass a besoin des deux autres instances pour fonctionner correctement, il est de la responsabilité de ImportantClass de s'assurer qu'elles sont dans un bon état avant tout autre événement.

2

Ce code viole plusieurs principes décrits dans l'excellent livre Effective Java de Joshua Bloch, que je recommande fortement. Par exemple, sur les champs d'instance publics:

Si un champ d'instance est non-finale, ou est une référence finale à un objet mutable, puis en faisant le domaine public, vous donnent la possibilité de limiter les valeurs qui peuvent être stockées dans le champ. Cela signifie que vous abandonnez également la possibilité d'appliquer des invariants impliquant le champ. En outre, vous abandonnez la possibilité de prendre n'importe quelle action lorsque le champ est modifié, donc les classes avec champs mutables publics ne sont pas thread-safe. Même si un champ est final et fait référence à un objet immuable, par rendant le champ public, vous abandonnez la possibilité de passer à une nouvelle représentation de données internes dans laquelle le champ n'existe pas.

De plus, vous n'obtenez pas d'encapsulation avec ces champs public.

Le livre a beaucoup à dire sur la façon de procéder à l'initialisation d'objets en toute sécurité et correctement.Qu'il suffise de dire, le code que vous avez posté est très problématique.

1

Vous pouvez lui mentionner que cette approche de codage viole l'un des trois concepts fondamentaux du développement orienté objet qui est bien sûr l'encapsulation.

Le fait que l'état de son objet peut être modifié directement par ses utilisateurs qui rend le débogage vraiment difficile, par opposition à une méthode privée qui sera la seule façon d'accéder aux données internes ...

Plus de cette , ses clients sont étroitement couplés avec sa classe donc dans le cas où il veut faire quelques changements internes ses clients ont besoin d'être recompilés malgré le fait que les changements survenus n'affectent pas leur utilisation ....

La vérité si , est que ces dernières années, l'application de l'encapsulation de données dans les systèmes OO a été assouplie par rapport au passé.

Des technologies telles que SPRING ou LINQ par exemple, enfreignent directement la confidentialité des détails d'implémentation en essayant d'archiver un comportement IOC ou «fonctionnel».

Un résultat direct de cette tendance est l'adoption récente de C# de propriétés automatiques qui sont utilisés pour simplifier l'exposition directe des données privées comme set/get propriétés ...

1

Il constitue une violation du Principle of Least Astonishment parce qu'en tant que consommateur la classe I nécessiterait une connaissance pratique de la classe pour le faire fonctionner sans exceptions (ou l'exécuter jusqu'à ce que je n'obtienne aucune exception ce qui serait une énorme douleur dans le $$).

Quelques citations de http://portal.acm.org/citation.cfm?id=1176622:

API doivent être faciles à utiliser et difficile à une mauvaise utilisation. Il devrait être facile de faire des choses simples; possible de faire des choses complexes; et impossible, ou du moins difficile, de faire de mauvaises choses.

Protégez les API des détails d'implémentation. Ils confondent les utilisateurs et inhibent la flexibilité d'évoluer. Il n'est pas toujours évident de savoir ce qu'est un détail de mise en œuvre: méfiez-vous de la surspécification.