Firma del metodo di interfaccia non abbastanza restrittiva

0

Ho scritto un pezzo di codice al mio lavoro qualche tempo fa. Mentre scrivevo il codice, scrivevo poche interfacce che mi permettevano di aggiungere più flessibilità e in quel momento stavo anche cercando di capire il concetto di OOP più in profondità. Quindi nell'interfaccia che ho scritto ho una firma del metodo simile a questa:

void Add(ImyBase objToAdd)

E quindi ho poche classi che implementano questa interfaccia. Ma quello che mi infastidisce è che mi trovo a fare questo genere di cose abbastanza spesso in questo metodo Add

public void Add(ImyBase objToAdd)
{
    if(!(objToAdd is ImyBaseDeviation))
        throw new ArgumentException("blablabla");

    //do stuff
}

All'epoca era un odore per me, ma non mi ero preoccupato di questo semplicemente perché sono solista su questo progetto e questo pezzo di codice è usato solo all'interno della mia compagnia e ci sono solo 2 ragazzi IT ( io + qualcun altro) e questo non è vicino a cambiare. Comunque recentemente sono tornato su quel pezzo di codice e dalla mia precedente lettura (in realtà più di questo, ma questo è abbastanza simile) ora mi sembra davvero male e sto cercando di capire il modo migliore per migliorare questo pezzo di codice.

Non mi piace il codice così com'è ora perché l'interfaccia consente più che il tipo concreto generalmente consente così sostanzialmente che l'implementazione del concret non rispetti il contratto dato dall'interfaccia.

I tough of a few solutions

Per prima cosa elimina semplicemente il metodo Add dall'interfaccia, poiché comunque chiamare Add ha un'alta probabilità di generare un'eccezione. Quindi per chiamare Add hai comunque bisogno del tipo concret. Quindi qui l'oggetto avrebbe ancora un metodo Add ma con il tipo accettato come parametro.

In secondo luogo aggiungi un metodo che assomiglierebbe a qualcosa di simile nell'interfaccia

bool IsValidToAdd(ImyBase objToTest)

Ma questo non mi soddisfa.

Quindi sto cercando consigli da persone più avanzate come te per aiutarmi a capire quale sarebbe il modo migliore per implementarlo, in modo che rimanga il più pulito possibile.

Scusa se non sono un anglofono nativo, quindi se la mia domanda necessita di editing o correzione della grammatica, per favore procedi. Grazie

    
posta Rémi 01.05.2014 - 02:27
fonte

2 risposte

1

Ti stai concentrando su quell'unica interfaccia, ma hai a disposizione almeno quattro diversi punti di personalizzazione:

  • L'interfaccia stessa.
  • Il codice che implementa l'interfaccia.
  • Il codice che chiama Add .
  • ImyBase e le sue derivate.

Non hai fornito abbastanza informazioni su questi ultimi due, ma probabilmente è dove si trova la tua soluzione, dal momento che non sei riuscito a trovare una soluzione soddisfacente usando solo i primi due. Alcune possibili soluzioni sono:

  • Cerca nell'uso di classi o metodi parametrizzati (quelli con <Type> ) per limitare i tipi evitando comunque la duplicazione.
  • Sposta alcune funzionalità dalle tue classi concrete implementando Add negli oggetti ImyBase . Generalmente, gli oggetti simili a contenitori traggono vantaggio dall'essere il più generico possibile, facendo solo cose da container e nient'altro.
  • Prova a spostare Add sull'oggetto ImyBase . A volte invertendo chi viene aggiunto a chi semplifica il codice o almeno aiuta ad aprire gli occhi ad altre possibilità, motivo per cui è utile come esercizio.

Sei sulla strada giusta con i tuoi criteri per un buon design. Dovresti essere in grado di trovare una soluzione che utilizza il sistema di tipi invece di un controllo manuale.

    
risposta data 01.05.2014 - 15:09
fonte
0

Non è una domanda facile rispondere senza alcuni esempi, ma vedo tre modi in cui puoi andare, a seconda degli effettivi scenari in uso.

  1. Elimina ImyBase . È possibile sostituire specifici (o tutti) usi con ImyBaseDeviation e rimuoverli da qualsiasi posizione in cui non è stato utilizzato.
    Fai questo se: non c'è nulla che usi ImyBase che non richiede anche qualcosa in ImyBaseDeviation (come una seconda implementazione diversa di ImyBase , ad esempio IAnimal - > ICat e IDog ).
  2. Recupera le cose da ImyBaseDeviation in ImyBase . Avrai bisogno di tirare abbastanza funzionalità che tutto dovrebbe chiaramente richiedere l'una o l'altra. Ricorda, puoi usare l'interfaccia meno specifica ovunque ti aspetti quella più specifica.
    Fai questo se: le due interfacce in realtà significano cose diverse (come IAnimal - > IHerbivore ).
  3. Fai # 2, ma "ombreggia" i metodi dell'interfaccia di base nello specifico. Questo succede molto con i generici. Potrebbe esserci un'interfaccia IFoo :

    interface IFoo
    {
      object GetValue();
    }
    
    interface IFoo<T> : IFoo
    {
      new T GetValue();
    }
    

    Questo è il modo in cui IEnumerable<T> lo gestisce, ad esempio.
    Fai questo se: i due sono strettamente correlati, ma uno usa un tipo più specifico dell'altro.

Spero che questo ti metta nella giusta direzione, almeno.

    
risposta data 01.05.2014 - 05:27
fonte

Leggi altre domande sui tag