Programmazione su interfacce orientate ai dati


9

C'è una parte della nostra base di codice scritta nel seguente stile:

// 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.
}

Cioè, ci sono un gran numero di interfacce che specificano solo un insieme di proprietà senza comportamento ognuna con un'unica implementazione corrispondente che le implementa con proprietà automatiche. Il codice è scritto da qualcuno abbastanza senior (molto più di me) ed è a parte questo codice procedurale ragionevole di interfacce. Mi chiedevo se qualcun altro avesse incontrato / usato questo stile e se avesse qualche vantaggio rispetto al semplice utilizzo di DTO concreti ovunque senza le interfacce.


1
Uno dei motivi per cui ho fatto questo è per la compatibilità COM, ma questo non sembra essere il tuo motivo qui.
Mike

@Mike Interessante, non ho mai usato COM e non è usato qui. Chiederò all'autore di questa sezione del codice se stava pianificando di usare la COM o altro.
walpen

La mia ipotesi sarebbe che si aspetta di rendere almeno una di quelle proprietà non auto in un futuro relativamente vicino, e scrivere questa piastra di partenza all'inizio è un'abitudine che ha preso per risparmiare un po 'di tempo a giocherellare in seguito, anche se sono non è un ragazzo C # quindi è tutto ciò che posso dire.
Ixrec,

6
IMHO è l'ossessione e l'errata applicazione del codice alle interfacce e non all'implementazione . Una chiave di volta è l'unica implementazione . Il punto di interfaccia è il polimorfismo, ma una classe di sole proprietà è polimorfica in un certo senso semplicemente avendo valori diversi. Anche con il comportamento - metodi - non ha senso dare una sola implementazione. Questa assurdità è presente in tutta la nostra base di codice e, nella migliore delle ipotesi, ostacola la manutenzione. Perdo troppo tempo a chiedere perché, cosa e dove. Perché l'hanno fatto, quale disegno non vedo e dove sono le altre implementazioni?
radarbob,

2
La maggior parte dei commenti precedenti va al singolo "odore di codice" di implementazione dell'astrazione prematura; tuttavia, c'è anche un modello di dominio anemico "odore di codice" qui, vedi: martinfowler.com/bliki/AnemicDomainModel.html
Erik Eidt

Risposte:


5

Ecco i miei due centesimi:

  • Non siamo sicuri che un DTO non avrà mai almeno un po 'di comportamento. Quindi per me ci sono oggetti che potrebbero avere o meno comportamenti in futuro.
  • Una causa possibile di avere tanti classi suola-implementazione è una mancanza di progettazione , ad esempio omettendo di vedere che ScheduledTask, ScheduledJob, ScheduledEvent, ScheduledInspection, ecc, dovrebbe essere solo uno segregati Schedulableinterfaccia effettuare qualsiasi schedulabile implementor.
  • Creare prima le interfacce è un'ottima pratica, ti dà un'idea di ciò di cui hai bisogno. Molte interfacce iniziano senza avere alcuna implementazione. Quindi qualcuno scrive un'implementazione e ce l'hanno. Lo stato di avere un'unica implementazione è temporaneo se si evita ciò che menziono nel secondo punto. Come fai a sapere in anticipo che alcune interfacce non avranno mai una seconda della terza implementazione?
  • Il nome che scegliamo per un'interfaccia ben pensata ha la tendenza a non cambiare in futuro, quindi le dipendenze da tale interfaccia non saranno influenzate. D'altra parte una classe concreta tende a essere rinominata quando cambia qualcosa di importante nel modo in cui viene implementata, ad esempio una classe concreta chiamata TaxSheetpotrebbe cambiare SessionAwareTaxSheetperché è stata fatta una revisione significativa ma ITaxSheetprobabilmente l'interfaccia non verrà rinominata così facilmente.

Linea di fondo:

  • Le buone pratiche di progettazione si applicano anche ai DTO.
  • I DTO possono essere aggiunti un po 'di comportamento lungo la strada.
  • Ogni interfaccia inizia con una sola implementazione.
  • D'altra parte, se hai troppe combo con una sola interfaccia e una classe, potrebbe esserci una mancanza di design che dovrebbe essere sottolineato. La tua preocupazione può essere giustificata .

4
Ho votato a favore della tua risposta, ma il tuo secondo proiettile implica che tutte le classi dovrebbero avere automaticamente un'interfaccia corrispondente, una posizione che non ho mai concordato. Scrivere interfacce nel caso in cui tu possa avere una seconda implementazione causa semplicemente la proliferazione dell'interfaccia e YAGNI.
Robert Harvey,

1

Un problema particolare che ho riscontrato con DTO che utilizzano interfacce è che consente questo:

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; } }
}

Ho visto questo schema applicato come un trucco rapido e sporco per implementare un comportamento critico. Questo porta a un codice che può avere un comportamento molto confuso:

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

Questo è difficile da mantenere e confuso per cercare di districare o refactoring. IMO, l'aggiunta di comportamenti ai DTO viola il principio della singola responsabilità. Lo scopo di un DTO è rappresentare i dati in un formato che può essere persistito e popolato da un quadro di persistenza.

I DTO non sono modelli di dominio. Non dovremmo preoccuparci se i DTO sono anemici. Per citare la discussione di Martin Fowler sul modello di dominio anemico :

Vale anche la pena sottolineare che l'inserimento del comportamento negli oggetti del dominio non dovrebbe contraddire il solido approccio dell'utilizzo della stratificazione per separare la logica del dominio da cose come la persistenza e le responsabilità di presentazione.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.