Modelli di progettazione per l'implementazione di funzionalità supportate facoltativamente

4

Ecco il problema originale. Esistono due classi: Protocollo e, ad esempio, ProtocolUser (che utilizza actully l'istanza della classe Protocol). Ora, ho bisogno di supportare più protocolli, le cui serie di funzioni si intersecano solo parzialmente, facendo cose simili ma non uguali. Ho raggruppato le funzionalità in diverse interfacce. Cioè:

interface IA {}
interface IB {}
interface IC {}

interface IP {};
class P_AB : IP, IA, IB {}
class P_AC : IP, IA, IC {}
class P_BC : IP, IB,IC {}

class P_User
{
    IP m_p;

    ??? // needs to use m_p via IA, IB or IC, depending on which are supported
}

E la parte più contraria: i protocolli devono essere attivati al volo. I metodi di P_User dovranno scegliere su quali interfacce operare, a seconda di quale sarà supportato dal tempo di chiamata.

Il piano iniziale era affidarsi a is & as operatori. Ma sembra sospettosamente ingombrante. L'unica alternativa che vedo è inventare una sorta di infrastruttura "CanDoThis / CanDoThat", ma non differisce molto da un semplice is .

Ci sono degli schemi utili di cui non sono a conoscenza?

    
posta vines 26.05.2015 - 15:36
fonte

3 risposte

2

Hai davvero due opzioni qui:

  • factoring - isola le interfacce di ogni oggetto e usa soft casting (come operatore) per determinare le funzionalità estese della classe
  • modello di caratteristica opzionale - implementa tutti i metodi disponibili su tutte le classi in una classe base e lancia NotSupportedException quando la funzione data non è supportata.

Entrambi hanno i loro pro e contro: Factoring:

  • pro: le responsabilità / capacità del tuo codice sono ben separate
  • con: il codice diventa più complesso e le funzionalità difficili da scoprire

Modello di funzioni opzionali:

  • pro: la funzionalità è più facile da scoprire utilizzando strumenti come Intellisense
  • con: la classe base è gonfia di funzioni inutili che potrebbero generare

Dato che hai detto che le tue interfacce dovrebbero intersecare solo un po ', vorrei seguire l'approccio del factoring, è più adatto per questi casi. Sarebbe necessario un esempio più realistico per darti una risposta più dettagliata.

Modifica: se ci si aspetta che alcune combinazioni di interfacce vengano utilizzate più di altre, è possibile combinarle in un'altra interfaccia:

public interface IAB : IA, IB

Ciò comporterebbe naturalmente un'esplosione dell'interfaccia se lo facessi per ogni combinazione possibile, quindi usalo con parsimonia solo nei casi in cui ha davvero senso. È sempre più facile aggiungere una nuova interfaccia piuttosto che rimuoverne una.

    
risposta data 26.05.2015 - 22:15
fonte
4

Inversione di dipendenza dovrebbe essere la soluzione migliore per il tuo caso.

Le interfacce non dovrebbero essere definite in base alle funzionalità supportate, ma su cosa P_User si aspetta dal protocollo. Ogni protocollo può quindi implementare ciò che P_User necessita in base alle sue capacità.

    
risposta data 26.05.2015 - 16:20
fonte
2

Quello che potresti fare è una variazione di una fabbrica astratta. Qualcosa del genere:

public class ProtocolFactory
{
    public IP _protocol;

    public ProtocolFactory(IP protocol)
    {
         _protocol = protocol;
    }

    public IA GetAService()
    {
         return _protocol as IA ?? new NoOpProtocol();
    }

    public IB GetBService()
    {
         return _protocol as IB ?? new NoOpProtocol();
    }

    // etc
}

public class NoOpProtocol : IA, IB, IC
{
     // Implement all interfaces as no-ops
}

Quindi ora il tuo codice chiamante è

var factory = new ProtocolFactory(m_p);
factory.GetAService().DoStuff();
factory.GetBService().DoMore();
// etc

Questo sembra meno ingombrante, mantiene la funzionalità soft-casting in un unico posto, ma ti consente comunque l'estensibilità, con tutti i protocolli che desideri, ognuno dei quali implementa il numero di interfacce che desideri.

    
risposta data 28.05.2015 - 00:33
fonte

Leggi altre domande sui tag