Quanto incapsulare quando gli oggetti trattati sono abbastanza simili

0

Siccome ho risposto a domande relative alla progettazione orientata agli oggetti e a come ridurre la quantità di classi per assicurarmi che non ci sia un sacco di "confusione di classe" e ripetizione del codice, ho iniziato a dubitare di come molto incapsulamento è troppo incapsulamento e per lo stesso motivo quanto incapsulamento non è abbastanza incapsulamento.

Ecco uno scenario specifico. Uno dei più dolorosi, che ho già incontrato alcune volte, è quando si cerca di recuperare alcuni pezzi di dati simili dal database e, di conseguenza, anche gli oggetti e gli archivi di riga sembrano molto simili.

Questo fa sorgere una domanda su quanto dovrebbe incapsulare. Immagino che per gli oggetti entità si possa creare una classe base, ma per quanto riguarda i repository?

La maggior parte del codice di mappatura sarà simile, ma hai intenzione di mettere metà della mappatura nella classe base e metà della sottoclassi? Non che non puoi, ma per me personalmente è un odore di codice, nel senso che la tua classe base dovrebbe facilitare la creazione delle sue classi derivate, ma non aiutarle con la loro implementazione del metodo. Dovrebbe consentire loro di sovrascrivere i metodi, ma non dare loro metà della logica di mappatura e quindi lasciarli implementare il resto.

Preferiresti invece separare completamente i repository anche se fossero un po 'simili nella mappatura dei dati (gli oggetti entità sarebbero diversi per ciascun repository) o proverai a classarne una parte?

Fondamentalmente la mia lotta è questa:

Would you rather let each repository encapsulate all that it needs for itself even if some of it might be similar to other repositories?

o

Would you rather base class it by getting rid of the duplication and as a result have that strange design where a base class provides half the logic and the subclasses take care of the rest?

Esempio:

public class RepositoryA
{
    private EntityObjectA load()
    {
         // load from db by calling a stored procedure
         // once loaded we do mapping
     }
 }

public class RepositoryB
{
    private EntityObjectB load()
    {
        // load from db by calling a stored procedure
        // once loaded we do mapping
    }
}

public class RepositoryC
{
    private EntityObjectC load()
    {
        // load from db by calling a stored procedure
        // once loaded we do mapping
    }
}

public class EntityObjectA
{
    public string field1 { get; set; }
    public string field2 { get; set; }
    public string field3 { get; set; }
}

public class EntityObjectB
{
    public string field1 { get; set; }
    public string field2 { get; set; }
    public string field3 { get; set; }
    public string field4 { get; set; }
    public string field5 { get; set; }
}

public class EntityObjectC
{
    public string field1 { get; set; }
    public string field2 { get; set; }
}

Ora creerai una base di partenza come EntityObjectBase?

Che posso ancora capire ma per quanto riguarda i repository?

Voglio dire che puoi praticamente vedere la mappatura sarà abbastanza simile ma vale la pena provare a combinarli?

Quanto vai lontano con l'incapsulamento perché in questo caso ci sarà qualche ripetizione del codice se non lo facciamo, ma se lo facciamo otteniamo un tipo strano di design.

    
posta AvetisG 22.03.2015 - 04:24
fonte

1 risposta

2

Not that you can't but for me personally it is a code smell in a sense that your base class is supposed to facilitate the creation of its derived classes but not help them with their method implementation.

Non sono sicuro che questa affermazione sia necessariamente vera.

Posso pensare a molti esempi in cui è accettato per le classi base di fornire funzioni utili all'implementazione interna delle classi estendendole. Forse un esempio banale potrebbe essere qualcosa come un metodo toString () o equals () che è spesso utile all'implementazione interna delle classi child. Inoltre, il modificatore di accesso protetto è esplicitamente inteso per lo scenario in cui una funzione dovrebbe essere accessibile a un bambino internamente ma non esternamente.

Nel tuo caso, penso che si possa usare una combinazione di un modello di metodo modello e di generici. La funzione load appartiene alla classe astratta, chiamerebbe una funzione protetta getStoredProc () (non implementata nella classe abstract) e restituisce un tipo generico. Quindi l'implementazione effettiva deve solo implementare il metodo getStoredProc () e definire il tipo.

    
risposta data 22.03.2015 - 06:14
fonte