Come organizzare al meglio i file di classe e di interfaccia?

5

OK .. dopo tutta la discussione sto cambiando leggermente la mia domanda per riflettere meglio un esempio concreto di cui mi sto occupando.

Ho due classi ModelOne e ModelTwo , Queste classi eseguono un tipo simile di funzionalità ma non sono correlate tra loro. Tuttavia, ho una terza classe CommonFunc che contiene alcune funzionalità pubbliche implementate sia in ModelOne che in ModelTwo e sono state scomposte per DRY . I due modelli sono istanziati all'interno della classe ModelMain (che a sua volta è istanziata a un livello superiore ecc. - ma mi fermo a questo livello).

Il contenitore IoC che sto utilizzando è Microsoft Unity . Non pretendo di essere un esperto in questo, ma la mia comprensione di questo è che si registra una tupla di interfaccia e classe con il contenitore e quando si desidera una classe concreta si chiede al contenitore IoC qualsiasi oggetto corrisponda a un'interfaccia specifica. Ciò implica che per ogni oggetto che voglio istanziare da Unity, ci deve essere un'interfaccia di corrispondenza. Poiché ciascuna delle mie classi esegue funzionalità diverse (e non sovrapposte), ciò significa che esiste un rapporto 1: 1 tra l'interfaccia e la classe 1 . Comunque non significa che sto scrivendo pedissequamente un'interfaccia per ogni classe che scrivo.

Quindi il codice saggio finirà con 2 :

public interface ICommonFunc 
{ 
}

public interface IModelOne 
{ 
   ICommonFunc Common { get; } 
   .. 
}

public interface IModelTwo
{ 
   ICommonFunc Common { get; } 
   .. 
}

public interface IModelMain 
{ 
  IModelOne One { get; } 
  IModelTwo Two { get; } 
  ..
}

public class CommonFunc : ICommonFunc { .. }

public class ModelOne : IModelOne { .. }

public class ModelTwo : IModelTwo { .. }

public class ModelMain : IModelMain { .. }

La domanda riguarda come organizzare la mia soluzione. Devo tenere insieme la classe e l'interfaccia? O dovrei tenere insieme le classi e le interfacce? EG:

Opzione 1 : organizzata per nome della classe

MySolution
  |
  |-MyProject
  |   |
      |-Models
      |   |
          |-Common
          |   |
          |   |-CommonFunc.cs
          |   |-ICommonFunc.cs
          |
          |-Main
          |   |
          |   |-IModelMain.cs
          |   |-ModelMain.cs
          |
          |-One
          |   |
          |   |-IModelOne.cs
          |   |-ModelOne.cs
          |
          |-Two
              |
              |-IModelTwo.cs
              |-ModelTwo.cs
              |

Opzione 2 - Organizzato per funzionalità (principalmente)

MySolution
  |
  |-MyProject
  |   |
      |-Models
      |   |
          |-Common
          |   |
          |   |-CommonFunc.cs
          |   |-ICommonFunc.cs
          |
          |-IModelMain.cs
          |-IModelOne.cs
          |-IModelTwo.cs
          |-ModelMain.cs
          |-ModelOne.cs
          |-ModelTwo.cs
          |

Opzione 3 - Interfaccia e implementazione sepa- ratrice

MySolution
  |
  |-MyProject
      |
      |-Interfaces
      |   |
      |   |-Models
      |   |   |
      |       |-Common
      |       |   |-ICommonFunc.cs
      |       |
      |       |-IModelMain.cs
      |       |-IModelOne.cs
      |       |-IModelTwo.cs
      |
      |-Classes
          | 
          |-Models
          |   |
              |-Common
              |   |-CommonFunc.cs
              |
              |-ModelMain.cs
              |-ModelOne.cs
              |-ModelTwo.cs
              |

Opzione 4 - Prendendo ulteriormente l'esempio di funzionalità

MySolution
  |
  |-MyProject
  |   |
      |-Models
      |   |
          |-Components
          |   |
          |   |-Common
          |   |   |
          |   |   |-CommonFunc.cs
          |   |   |-ICommonFunc.cs
          |   |   
          |   |-IModelOne.cs
          |   |-IModelTwo.cs
          |   |-ModelOne.cs
          |   |-ModelTwo.cs
          |
          |-IModelMain.cs
          |-ModelMain.cs
          |

Ho una sorta di antipatia opzione 1 a causa del nome della classe nel percorso. Ma dato che ho un rapporto 1: 1 a causa della mia scelta / utilizzo IoC (e che può essere discutibile) questo ha dei vantaggi nel vedere la relazione tra i file.

L'opzione 2 mi piace, ma ora ho confuso le acque tra ModelMain e sotto-modelli.

L'opzione 3 funziona per separare la definizione dell'interfaccia dall'implementazione, ma ora ho queste interruzioni artificiali nei nomi dei percorsi.

Opzione 4. Ho preso l'Opzione 2 e l'ho ottimizzata per separare i componenti dal modello principale.

C'è una buona ragione per preferire uno rispetto all'altro? O qualsiasi altro potenziale layout che mi è sfuggito?

1. Frank ha fatto un commento sul fatto che il rapporto 1: 1 si riferisce ai giorni C ++ di file .h e .cpp. So da dove viene. La mia comprensione dell'Unità sembra mettermi in questo angolo, ma non sono nemmeno sicuro di come uscirne se si segue anche l'adagio di Program to an interface Ma questa è una discussione per un altro giorno.

2. Ho omesso i dettagli di ogni costruttore di oggetti. È qui che il contenitore IoC inietta gli oggetti come richiesto.

    
posta Peter M 26.07.2017 - 22:35
fonte

3 risposte

4

Dal momento che un'interfaccia è astratta- mente simile a una classe base, usa la stessa logica che useresti per una classe base. Le classi che implementano un'interfaccia sono strettamente correlate all'interfaccia.

Dubito che preferiresti una directory chiamata "Base Classes"; la maggior parte degli sviluppatori non lo vorrebbe, né una directory chiamata "Interfacce". In c #, le directory sono anche spazi dei nomi per impostazione predefinita, il che rende doppiamente confuso.

L'approccio migliore è quello di pensare a come suddividere le classi / interfacce se dovessi metterne in una libreria separata e organizzare i namespace / directory in modo simile. Le linee guida di progettazione di .net hanno suggerimenti dello spazio dei nomi che possono essere utile.

    
risposta data 27.07.2017 - 00:53
fonte
1

Prendo il secondo approccio, con altre cartelle / spazi dei nomi in progetti complessi, naturalmente. Significa che disaccoppia le interfacce dalle implementazioni concrete.

In un progetto diverso, potrebbe essere necessario conoscere la definizione dell'interfaccia, ma non è affatto necessario conoscere alcuna classe concreta che la implementa, specialmente quando si utilizza un contenitore IoC. Quindi questi altri progetti devono solo fare riferimento ai progetti di interfaccia, non ai progetti di implementazione. Questo può mantenere bassi i riferimenti e può prevenire problemi di riferimento circolari.

    
risposta data 27.07.2017 - 11:08
fonte
1

Come sempre con qualsiasi domanda di design, la prima cosa da fare è determinare chi sono i tuoi utenti. Come useranno la tua organizzazione?

Sono programmatori che useranno le tue lezioni? Quindi separare le interfacce dal codice potrebbe essere il migliore.

Sono i manutentori del tuo codice? Quindi mantenere le interfacce e le classi insieme può essere il migliore.

Siediti e crea alcuni casi d'uso. Quindi la migliore organizzazione potrebbe apparire prima di te.

    
risposta data 30.07.2017 - 03:36
fonte

Leggi altre domande sui tag