Implementazioni separate o una con tutte le funzionalità

0

Attualmente sto creando moduli di importazione Excel per alcuni dati complessi. Non ho pianificato bene e ho incontrato problemi di riutilizzo del codice. Ho realizzato i primi moduli e ho capito che i prossimi moduli avranno bisogno di alcuni metodi da questi che ho già realizzato. La mia prima opzione era di risolverla con una gerarchia di ereditarietà semplice. Sfortunatamente non potevo farlo, perché alcune sottoclassi avevano bisogno di funzioni da due superclassi, il che significa che dovevo usare l'ereditarietà multipla, che non è supportata nel linguaggio che uso (C #). L'unico altro modo per risolverlo che potevo pensare era quello di creare più interfacce e le loro implementazioni per ogni metodo che dovevo riutilizzare. L'ho fatto e l'aspetto della struttura completa ora è il seguente:

public interface IImportAssistant<TReturn, TSearchKey>
{
    bool TryGetNewOrChanged(TSearchKey searchKey, out TReturn object);
}

public interface IMaterialImportAssistant : IImportAssistant<Material, string>
{
}

public interface ICustomerImportAssistant : IImportAssistant<Customer, string>
{
}

public class MaterialImportAssistant : IMaterialImportAssistant
{
    public bool TryGetNewOrChanged(
    string materialId,
    Dictionary<string, Material> materialToIdMappings,
    Dictionary<string, MaterialServiceItemDto> materialFromServiceToIdMappings,
    out Material material)
    {
         bool materialFoundInService = materialFromServiceToIdMappings.TryGetValue(materialId, out MaterialFromServiceItemDto materialFromService);
         if (!materialFoundInService)
             throw new ImportValidationException("Material could not be found");

         bool materialFound = materialToIdMappings.TryGetValue(materialId, out material);
         if (materialFound)
         {
              if (material.Name == materialFromService.Name
                  && material.SupplyProducerName == materialFromService.SupplyProducerName
                  && material.SupplyProducerId == materialFromService.SupplyProducerId)
                     return false;

             material.Name = materialFromService.Name;
             material.SupplyProducerName = materialFromService.SupplyProducerName;
             material.SupplyProducerId == materialFromService.SupplyProducerId;

             return true;
         }
         else
         {
             material = new Material()
             {
                  Name = materialFromService.Name,
                  SupplyProducerName = materialFromService.SupplyProducerName,
                  SupplyProducerId == materialFromService.SupplyProducerId
             };

             return true;
         }
    }
}

public class CustomerImportAssistant : ICustomerImportAssistant
{
     //Code simmilar to material but with Customer entity
}

Esistono altre implementazioni per ciascuna entità che ho dovuto inserire nel mio sistema da un file excel. Come puoi vedere, verifica se l'entità esiste nel sistema esterno, quindi controlla se è già presente nel nostro database e se è stata modificata. È un metodo semplice, ma non volevo copiarlo incollandolo in ogni modulo di importazione, che deve controllare l'entità data. Ora, mentre lo guardo e oltre una dozzina di interfacce e le loro implementazioni, mi chiedo se dovrei fare solo una grande interfaccia e implementazione per tutti questi metodi. Il vantaggio che posso vedere sono meno file con codice e meno dipendenza da iniettare nelle classi di costruzione. Lo svantaggio è che sarebbe come un sacchetto funzionale, che è contro la responsabilità di una singola classe e le linee guida generali OOP. Sono un programmatore principiante e penso di conoscere bene gli strumenti linguistici, ma mi manca una prospettiva più ampia e le mie azioni postumi, quindi impatto sulla manutenibilità e sull'espansibilità di ciò che faccio. Potresti dirmi se ci sono altri vantaggi o svantaggi di entrambe le animazioni? O forse c'è qualche altro schema di progettazione, che risolve questi casi? Quali sono le migliori pratiche in tali situazioni?

    
posta helvy91 17.03.2018 - 11:57
fonte

3 risposte

1

Pensa funzionale, non orientata agli oggetti. Le tecniche funzionali forniscono una soluzione per l'ereditarietà multipla. Le tue coppie di interfaccia / implementazione sono essenzialmente le stesse delle funzioni di prima classe.

Raccogli tutto il codice comune in un unico metodo, quindi il codice della variabile può andare in metodi sovrascritti (le interfacce non aiutano molto qui) o fornito tramite parametri di funzione o azione.

    
risposta data 22.03.2018 - 23:02
fonte
0

C'è una terza soluzione qui. La differenza tra ogni implementazione del metodo nel tuo esempio è la mappatura delle proprietà. Crea un tipo base per le tue DTO e le tue classi client con metodi che caricano i dati dal DTO nell'oggetto client. È quindi possibile sovrascrivere i metodi nelle classi derivate per astrarre la mappatura delle proprietà tra DTO e oggetti client.

    
risposta data 22.05.2018 - 11:55
fonte
0

Questo codice funziona come un framework ORM: qui il recupero dei dati. Ne userei uno invece. Quindi, presta attenzione ai criteri R delle operazioni CRUD - qui materiale / ID cliente e aspetto di ottenere oggetto materiale / cliente effettivo.

Se ORM non è un'opzione che reinventare la ruota. Un modo è quello di fornire file di mappatura nel formato JSON / XML / ... ad es. class="Materiale", proprietà="nome", ... che può essere letto da un meccanismo di recupero generale. Una soluzione più integrata con C # può concentrarsi sugli attributi C # invece di mappare i file. Il miglioramento sarebbe la lettura delle proprietà dalla classe del modello. Il risultato finale:

Material material = yourORMakaImportAssistant.createQuery(typeof(Material), materialID);
    
risposta data 22.05.2018 - 15:23
fonte