Torna storia:Refactoring .NET, ASCIUTTO. doppia eredità, l'accesso ai dati e la separazione degli interessi
così mi è stato bloccato su un problema di architettura da un paio di notti su un refactoring che ho accarezzato. Niente di importante, ma mi ha infastidito. In realtà è un esercizio in DRY e un tentativo di portarlo a un livello così estremo come l'architettura DAL è completamente SECCO. È un esercizio completamente filosofico/teorico.
Il codice è basato in parte su uno dei refactoring di @JohnMacIntyre che recentemente l'ho convinto a scrivere su http://whileicompile.wordpress.com/2010/08/24/my-clean-code-experience-no-1/. Ho modificato leggermente il codice, come tendo, al fine di portare il codice un ulteriore livello - di solito, solo per vedere quale chilometraggio extra posso ottenere da un concetto ... comunque, le mie ragioni sono in gran parte irrilevanti.
Parte del mio strato di accesso ai dati si basa sulla seguente architettura:
abstract public class AppCommandBase : IDisposable { }
Questo contiene cose di base, come la creazione di un oggetto di comando e di pulitura dopo l'AppCommand viene smaltito. Tutti i miei oggetti di comando derivano da questo.
abstract public class ReadCommandBase<T, ResultT> : AppCommandBase
Questo contiene cose di base che colpisce tutti i read-comandi - in particolare in questo caso, la lettura dei dati da tabelle e viste. Nessuna modifica, nessun aggiornamento, nessun salvataggio.
abstract public class ReadItemCommandBase<T, FilterT> : ReadCommandBase<T, T> { }
Questo contiene alcune cose generiche più di base - come la definizione di metodi che saranno necessarie per leggere un singolo elemento da una tabella del database, in cui il nome della tabella, il nome campo chiave ed elenco campo nomi sono definiti come richieste proprietà astratte (da definire dalla classe derivata.
public class MyTableReadItemCommand : ReadItemCommandBase<MyTableClass, Int?> { }
Questo contiene proprietà specifiche che definiscono il mio nome della tabella, l'elenco dei campi della tabella o vista, il nome del campo chiave, un metodo per analizzare i dati fuori dalla riga IDataReader nel mio oggetto business e un metodo che avvia l'intero processo
Ora, ho anche questa struttura per il mio ReadList ...
abstract public ReadListCommandBase<T> : ReadCommandBase<T, IEnumerable<T>> { }
public class MyTableReadListCommand : ReadListCommandBase<MyTableClass> { }
La differenza è che le classi elenco contengono le proprietà che appartengono alla lista generazione (vale a dire Page Start, PageSize, Sort e restituisce un oggetto IEnumerable) rispetto al ritorno di un singolo DataObject (che richiede solo un filtro che identifica un record univoco).
Problema:
sto odiando che ho un sacco di immobili a mia classe MyTableReadListCommand che sono identici nella mia classe MyTableReadItemCommand. Ho pensato di spostarli in una classe helper, ma mentre ciò potrebbe centralizzare i contenuti dei membri in un posto, avrò comunque membri identici in ciascuna classe, che invece puntano alla classe helper, che ancora non mi piace.
Il mio primo pensiero era la duplice ereditarietà che avrebbe risolto questo problema, anche se sono d'accordo sul fatto che la doppia ereditarietà sia di solito un odore di codice - ma risolverebbe questo problema in modo molto elegante. Quindi, dato che .NET non supporta la doppia ereditarietà, da dove vado?
Forse un altro refactor sarebbe più adatto ...ma sto avendo problemi a sistemare la mia mente su come superare questo problema.
Se qualcuno ha bisogno di una base di codice completa per vedere su cosa sto insistendo, ho una soluzione prototipo sul mio DropBox allo http://dl.dropbox.com/u/3029830/Prototypes/Prototype%20-%20DAL%20Refactor.zip. Il codice in questione si trova nel progetto DataAccessLayer.
P.S. Questo non fa parte di un progetto attivo in corso, è più un puzzle refactoring per il mio stesso divertimento.
Grazie in anticipo gente, lo apprezzo.
Per riferimento, la soluzione non vi piace è conosciuto come il modello di delega: http://en.wikipedia.org/wiki/Delegation_pattern. –
anche: http://stackoverflow.com/questions/1224830/difference-between-strategy-pattern-and-delegation-pattern.Mi piace l'approccio di mson sul modello: "la delega implica che invece di avere un singolo oggetto responsabile di tutto, delega le responsabilità ad altri oggetti, il motivo per cui questa è una tecnica comune è che impone due principi ancora più fondamentali dello sviluppo del software riducendo l'accoppiamento e aumentando la coesione. " –
Non sono sicuro se sia meglio abbandonare questo progetto e inventarne uno completamente nuovo, o rifattorizzarlo per inventare qualcosa che abbia senso. L'uso crescente di generici come parametri di tipo all'interno di una definizione generica è un segno sicuro che stai seguendo una linea molto sottile tra chiarezza e follia. Sono tentato di dire "usa NHibernate ..." oh aspetta lì l'ho detto ... –