Programmation vers des interfaces orientées données

9

Il y a une partie de notre base de code écrite dans le style suivant:

// IScheduledTask.cs
public interface IScheduledTask
{
    string TaskName { get; set; }
    int TaskPriority { get; set; }
    List<IScheduledTask> Subtasks { get; set; }
    // ... several more properties in this vein
}

// ScheduledTaskImpl.cs
public class ScheduledTaskImpl : IScheduledTask
{
    public string TaskName { get; set; }
    public int TaskPriority { get; set; }
    public List<IScheduledTask> Subtasks { get; set; }
    // ... several more properties in this vein, 
    // perhaps a constructor or two for convenience.
}

C'est-à-dire qu'il existe un grand nombre d'interfaces spécifiant juste un ensemble de propriétés sans comportement chacune avec une implémentation correspondante unique qui les implémente avec des auto-propriétés. Le code est écrit par une personne assez âgée (beaucoup plus que moi) et est en dehors de cette utilisation d'interfaces de code procédural raisonnable. Je me demandais si quelqu'un d'autre avait rencontré / utilisé ce style et s'il avait des avantages par rapport à l'utilisation de DTO concrets partout sans les interfaces.

walpen
la source
1
L'une des raisons pour lesquelles je l'ai fait est la compatibilité COM, mais cela ne semble pas être votre raison ici.
Mike
@Mike Intéressant, je n'ai jamais utilisé COM et il n'est pas utilisé ici. Je vais demander à l'auteur de cette section du code s'il prévoyait d'utiliser le COM ou quoi que ce soit.
walpen
Je suppose qu'il s'attend à ce qu'au moins une de ces propriétés ne soit pas auto dans un avenir relativement proche, et écrire ce passe-partout au début est une habitude qu'il a prise pour gagner du temps à tripoter plus tard, bien que je sois pas un gars C # donc c'est tout ce que je peux dire.
Ixrec
6
À mon humble avis, c'est la sur-obsession et la mauvaise application du code aux interfaces et non la mise en œuvre . Un témoin clé est la seule mise en œuvre . Le point d'interfaces est le polymorphisme, mais une classe de propriétés uniquement est polymorphe dans un sens simplement en ayant des valeurs différentes. Même avec un comportement - des méthodes - cela ne sert à rien étant donné une seule implémentation. Ce non-sens est partout dans notre base de code et au mieux, il entrave la maintenance. Je perds trop de temps à me demander pourquoi, quoi et où. Pourquoi l'ont-ils fait, quelle conception ne vois-je pas et où sont les autres implémentations?
radarbob
2
La plupart des commentaires précédents concernent la seule "odeur de code" de l'implémentation de l'abstraction prématurée; cependant, il existe également un modèle de domaine anémique "odeur de code" ici, voir: martinfowler.com/bliki/AnemicDomainModel.html
Erik Eidt

Réponses:

5

Voici mes deux cents:

  • Nous ne sommes pas sûrs qu'un DTO n'aura jamais au moins un peu de comportement. Donc, pour moi, il y a des objets qui peuvent ou non avoir un comportement à l'avenir.
  • Une cause possible d'avoir tant de classes unique, la mise en œuvre est un manque de conception , par exemple ne pas voir que ScheduledTask, ScheduledJob, ScheduledEvent, ScheduledInspection, etc, ne devrait être qu'une ségrégation Schedulableinterface de faire une planifiable de implementor.
  • La création des interfaces en premier est une très bonne pratique, elle vous donne un aperçu de ce dont vous avez besoin. De nombreuses interfaces commencent par n'avoir aucune implémentation. Ensuite, quelqu'un écrit une implémentation et il en a une. L'état d'avoir une implémentation unique est temporaire si vous évitez ce que je mentionne dans le deuxième point. Comment savez-vous à l'avance qu'une interface n'aura jamais de deuxième ou troisième implémentation?
  • Le nom que nous choisissons pour une interface bien pensée a tendance à ne pas changer à l'avenir, donc les dépendances à cette interface ne seront pas affectées. D'un autre côté, une classe concrète est sujette à être renommée lorsque quelque chose d'important dans la façon dont elle est implémentée change, par exemple une classe concrète nommée TaxSheetpourrait changer en SessionAwareTaxSheetraison d'une refonte importante mais l'interface ITaxSheetne sera probablement pas renommée si facilement.

Conclusion:

  • Les bonnes pratiques de conception s'appliquent également aux DTO.
  • Les DTO peuvent être ajoutés un peu de comportement sur la route.
  • Chaque interface commence par avoir une seule implémentation.
  • En revanche, si vous avez trop de combos à une interface et à une classe, il pourrait y avoir un manque de conception qui devrait être souligné. Votre pré-occupation peut être justifiée .
Tulains Córdova
la source
4
J'ai surévalué votre réponse, mais votre deuxième puce implique que toutes les classes devraient automatiquement avoir une interface correspondante, une position avec laquelle je ne suis jamais d'accord. L'écriture d'interfaces au cas où vous pourriez avoir une deuxième implémentation ne fait que provoquer la prolifération des interfaces et YAGNI.
Robert Harvey
1

Un problème particulier que j'ai vu avec les DTO qui utilisent des interfaces est qu'il permet ceci:

public interface ISomeDTO { string SomeProperty { get; set; }}

public class SomeDTO : ISomeDTO
{
    public string SomeProperty { get; set; }
    string ISomeDTO.SomeProperty { get { /* different behavior */ } set { SomeProperty = value; } }
}

J'ai vu ce modèle appliqué comme un hack rapide et sale pour implémenter un comportement critique. Cela conduit à du code qui peut avoir un comportement très déroutant:

SomeDTO a = GetSomeDTO();
ISomeDTO ia = a;
Assert.IsTrue(a.SomeProperty == ia.SomeProperty); // assert fails!

C'est difficile à maintenir et déroutant pour essayer de démêler ou de refactoriser. OMI, l'ajout d'un comportement aux DTO viole le principe de responsabilité unique. Le but d'un DTO est de représenter les données dans un format qui peut être conservé et rempli par un cadre de persistance.

Les DTO ne sont pas des modèles de domaine. Nous ne devrions pas nous inquiéter si les DTO sont anémiques. Pour citer la discussion de Martin Fowler sur le modèle de domaine anémique :

Il convient également de souligner que le fait de mettre le comportement dans les objets du domaine ne doit pas contredire l'approche solide consistant à utiliser la superposition pour séparer la logique du domaine de choses telles que la persistance et les responsabilités de présentation.

Erik
la source