2010-03-24 12 views
1

Comme n'importe quel motif de conception, le Specification Pattern est un concept génial, mais susceptible d'être utilisé par un architecte/développeur passionné.Utilisation du motif de spécification

Je suis sur le point de commencer le développement sur une nouvelle application (.NET & C#) et aime vraiment le concept du modèle de spécification et je suis désireux de l'utiliser pleinement. Cependant, avant d'aller dans toutes les armes flamboyant, je serais vraiment intéressé de savoir si quelqu'un pourrait partager les points de douleur qui ont connu lors de l'utilisation du Specification Pattern dans le développement d'une application.

Idéalement, je suis à la recherche pour voir si d'autres ont eu des problèmes dans

  • tests unitaires d'écriture contre le modèle de spécification
  • Décider quelle couche les spécifications doivent vivre dans (référentiel, service, domaine, etc.)
  • En l'utilisant partout où une simple déclaration if aurait fait le travail
  • etc?

Merci à l'avance

+5

Cet article a été publié en 2006. Ce modèle est-il vraiment aussi utile maintenant que nous avons des lambdas en C#? –

+0

Je ne vois aucune utilisation/avantage à l'utiliser du tout, jamais. – fearofawhackplanet

+0

http://stackoverflow.com/questions/1454049/is-the-specification-pattern-obsolete-when-you-use-dynamic-linq –

Répondre

8

Comme David a souligné dans son commentaire, beaucoup de ce qui est utile sur la spécification peut maintenant être plus succinctement atteint avec les goûts de LINQ.

Au lieu d'un nouveau type de spécification, vous pouvez créer des spécifications arbitraires à la volée: GetCustomers().Where(customer => customer.IsActive && customer.City == "Oakland");

Ce n'est pas un remplacement complet pour la spécification, cependant, pour deux raisons:

  1. Le tri/filtrage s'effectue dans la classe consommatrice après le renvoi de tous les clients. Si vous travaillez avec autre chose que des objets en mémoire, ceci est sous-optimal (LINQ-to-SQL et autres sont des exceptions car ils compilent et optimisent les requêtes et les exécutent du côté serveur/distant, retournant seulement les résultats désirés).
  2. Votre API est ouverte à toute requête si vous exposez des collections et laissez la spécification aux requêtes LINQ. Si vous voulez limiter ce que vous pouvez extraire, vous aurez besoin d'un ensemble de spécifications avec lesquelles interroger.

Il n'y a certainement pas besoin de l'utiliser partout, et il est très possible que vous en aurez pas besoin du tout; Je ne connais pas votre domaine ni ce sur quoi vous travaillez.

Je pense que le meilleur conseil n'est pas de regarder pour l'utiliser. Vous verrez quand cela est justifié, le plus probable lorsque vous commencerez à écrire un cours qui ressemble au premier exemple de l'article auquel vous avez lié. Il suffit de le garder dans votre référentiel de schémas mentaux afin de l'avoir si vous en avez besoin; Si vous ne l'utilisez jamais, cela signifie seulement que vous n'en avez pas besoin, et c'est bien.

Le choix de la couche dépend de la nature des spécifications et de l'utilisation. Dans de nombreux cas, ils sont des aides à la prise en charge d'une couche de service, mais dans certains cas ils encapsulent la logique de domaine.

En ce qui concerne les tests unitaires, n'oubliez pas que vos spécifications sont des unités ou contiennent des unités.Ne pas tester une méthode qui accepte une spécification avec toutes les combinaisons de spécifications possibles; testez les spécifications elles-mêmes pour vous assurer qu'elles se comportent comme prévu, et vous pourrez réutiliser les mêmes spécifications en toute confiance dans de nombreuses méthodes et classes.

J'espère que c'est un peu utile.

+0

@Jay merci beaucoup pour votre réponse perspicace. Cheers Kane – Kane

+0

Pas de problème. Je dois aussi mentionner que l'utilisation de lambdas permet une forme de spécification supplémentaire par rapport à LINQ "côté client": passer des délégués anonymes comme arguments de méthode. 'GetCustomers (client => customer.IsActive && client.City == "Oakland"); ' – Jay

+0

@Jay Les spécifications sont censées encapsuler le sens métier et éviter la duplication de code. Je ne dis pas qu'ils devraient être utilisés partout, mais la propagation de lambdas autour de votre code n'est pas un remplacement pour ce que les spécifications sont censées vous acheter. – Wix

13

Je ne crois pas LINQ est un remplacement pour le modèle de spécification. N'oubliez pas qu'une spécification est mieux utilisée pour encapsuler la logique métier. Donc, si l'un de mes besoins d'affaires m'a obtenir tous les précieux clients pour plusieurs fonctions ma déclaration Linq peut ressembler à ceci:

var valuedCustomers = Customers.Where(c => c.Orders.Count > 15 && c.Active).ToList(); 

je peux taper cette déclaration sur mon application, mais si je veux ajouter à cette règle que le client doit avoir rejoint avant une date? Eh bien, maintenant je dois aller partout dans mon application et changer le Linq. Ou si le graphique de mon objet change (bien que cela ne soit pas la seule raison d'utiliser le motif). Au contraire, quand je pouvais faire quelque chose comme ça

var valuedCustomers = Customers.Where(new ValuedCustomerRule.IsSatisfied()).ToList(); 

Je suis d'accord que le modèle est plus utilisé, mais il est très utile pour les règles d'affaires qui apparaissent tout au long de votre système afin que vous ne soyez pas mordu quand ces règles changent. Pour moi, cela revient à laisser des requêtes SQL partout dans le code de votre application.

+1

pourquoi pas: var valucostumers = Customer.Where (c => c.IsValued()). ToList(); –

+0

Je suis d'accord avec @Wix. Mon opinion sur la comparaison de LINQ vs spécification: http://stackoverflow.com/a/34637613/890890 – fabriciorissetto

1

Je suis d'accord avec Wix, LINQ ne remplace pas le modèle de spécification. Je n'ai pas assez de réputation pour ajouter un commentaire à la réponse de Wix, je réponds simplement comme une réponse.

J'ai utilisé la spécification principalement dans le domaine et le référentiel et je l'ai trouvé très utile. Le modèle de spécification vous aidera à réutiliser la règle métier et à améliorer la lisibilité de la logique conditionnelle. Dans mon cas, le référentiel a compris le modèle de spécification, ce qui signifie que le filtrage a été effectué sur un serveur de base de données non utilisé. En utilisant specification pattern et référentiel générique vous pouvez écrire le code suivant dans style-

 var popular = new PopularProductSpecification(); 
     var keyboard = new CategorySpecification(ProductCategory.KeyBoard); 
     var popularKeyboard = popular.And(keyboard); 

     var popularKeyboards = _repository.Get(popularKeyboard); 

En fait, je l'ai étendu bit de motif autre spécification :) pour créer dynamic queries. Vous pouvez écrire le code suivant qui peut être utilisé pour soutenir un formulaire de recherche complexe avec un minimum code-

 string userSuppliedProperty = "AverageRating"; 
     OperationType userSuppliedOperationType = OperationType.GreaterThan; 
     var userSuppliedValue = 4.5; 

     var userFilter = new DynamicSpecification<Product>(userSuppliedProperty, userSuppliedOperationType, userSuppliedValue); 
     //you can combine userFilter with any other specification 
     var filteredProducts = _repository.Get(userFilter); 

Comme d'autres l'ont souligné, comme les autres modèles, il peut être être galvaudé alors ne forcez pas dans toutes les situations. Sentez-vous libre d'avoir une logique conditionnelle avec du code plain vanilla, des méthodes privées ou toute autre approche traditionnelle que vous avez utilisée pour gérer la logique conditionnelle. Je garderai également l'utilisation de la spécification limitée à l'implémentation interne d'une méthode et je ne la transmettrai pas dans les arguments de méthode publique, bien que dans mon exemple les méthodes de référentiel acceptent la spécification mais c'était le seul endroit dans le projet entier.