2010-11-15 15 views
5

Possiedo un set di classi, ognuna delle quali deve decidere a un certo punto quale di due o tre approcci utilizzare internamente per implementare esternamente la stessa funzionalità. Idealmente, questo dovrebbe includere la funzionalità di fallback, dove se ApproachA fallisce, cade per provare ApproachB (e forse si avvicina a C, D, ecc.). Fino ad ora, ho appena usato la codifica come if (!success) { ApproachB code }. Il problema con questo è che diversi metodi successivi devono anche essere a conoscenza di quale approccio è stato scelto e tutti sviluppano anche le proprie dichiarazioni if (MethodChosen) { } else { }. Voglio davvero affrontare il problema con qualcosa di meno ingombrante ... tranne che nessuna delle altre opzioni che ho considerato sembra tutta "maneggevole". Ecco i tre approcci che ho pensato:Implementazione di classi "fallback"

  1. Implementare un metodo .Create statico che decide quale delle due classi derivate creare, in cui le due classi dispongono di un'interfaccia che le supporta. Lo svantaggio di questo è che stai scrivendo due volte lo stesso codice, e in realtà non sta creando una "ripiego" poiché impone che tutto il processo decisionale venga eseguito in anticipo nel metodo .Create. Questo dovrebbe funzionare 9/10 volte, ma ci saranno le altre 1/10 volte in cui voglio che il fallback entri in gioco solo quando il primario ha tentato e fallito.
  2. Lo stesso come sopra, ma con una classe base o astratta coinvolta, sia come classe di supporto per entrambi, sia con il primario come classe base per il fallback. Questo ha lo stesso svantaggio di fallback, ma almeno c'è poco o nessun codice ripetuto.
  3. implementare una classe astratta normalmente costruita con classi figlie che può essere modificato in fase di esecuzione: cioè

    public void SomeMethodOrConstructor() 
    { 
        if (someConditions) 
         MyChild = ChildClassA; 
        else 
         MyChild = ChildClassB; 
    } 
    
    
    public void Execute() 
    { 
        MyChild.Execute(); 
    } 
    

Il problema con l'opzione 3 sta passando dati tra i due quando necessario. Poiché alcuni di questi metodi stanno modellando oggetti esterni, ciò sarà abbastanza frequente. Le classi nidificate condividono automaticamente i dati con la loro classe genitore? O dovrò passare tutto con ogni chiamata?

Qualcos'altro che dovrei considerare?


Aggiornamento: la prima classe è attiva e funzionante con la catena di responsabilità. Per ora, ho deciso di non utilizzare il modello di strategia o il fallback durante l'esecuzione del metodo, poiché credo che alla fine non sia necessario. Penso che la maggior parte di tali fallimenti di esecuzione saranno in effetti migliori se si manterranno all'interno delle proprie classi, dal momento che non ci sarà un cambio completo di gameplan, solo alcune piccole modifiche da affrontare. Se questo risulta non essere il caso, almeno so di cosa ho bisogno per indagare ora.

Grazie a tutti coloro che hanno contribuito con la soluzione definitiva!

Per i curiosi, la mia soluzione definitiva lavorato più o meno in questo modo:

  • Creare Handler classe astratta, più o meno come indicato nella voce di Wikipedia, ma con una funzione public abstract Handler GetHandler(), e l'aggiunta di altri metodi astratti come carico, Salva, ecc.
  • Implementare sottoclassi di handler privati ​​per la classe genitore (potrebbero anche essere sottoclassi, dato che gestiranno solo le cose per quella particolare classe ... eviteranno anche problemi di denominazione successivi). Le classi figlie prendono tutti un parametro del tipo dell'oggetto genitore nel loro costruttore, in modo da avere un facile accesso ai dati del genitore.
  • Dal costruttore della classe genitore, impostare Chain of Responsibility handler/successors (sempre, proprio come nell'esempio), quindi chiamare FirstHandler.GetHandler(this) e memorizzare il risultato in modo che la classe sappia quale gestore utilizzare in futuro.
  • La maggior parte dei metodi gestiti viene quindi ridotta a Handler.MethodName().
+2

È possibile inserire il codice in un elenco numerato indentandolo con _eight_ spazi. – SLaks

+0

Grazie per il suggerimento di formattazione, che mi stava guidando sul muro! – RobinHood70

risposta

5

Utilizzare Chain of Responsibility.

catena di responsabilità modello è un modello disegno composto da una fonte di oggetti comando e una serie di oggetti elaborazione. Ogni oggetto elaborazione contiene un insieme di logica che descritti i tipi di oggetti comando che può gestire e come passare quelli che non può gestire al oggetto successivo trasformazione nella catena. Esiste anche un meccanismo per aggiungere nuovi oggetti di elaborazione alla fine di questa catena .

Questo si adatta perfettamente a ciò che è necessario fare.

+0

Oggi ci giocherò, ma sono sicuro che questa è la risposta che stavo cercando! – RobinHood70

+0

Qualunque cosa, dammi solo un urlo. – Aliostad

+0

Qualche suggerimento su come implementarlo in termini di chiamate successive? Per mettere il mio caso specifico in un esempio più generico, supponiamo che disponga di un metodo Load e Save, dove Load gestisce file XML o TXT. Save non ha bisogno di "ridefinirlo", Load ha già determinato cosa sta gestendo. Sto pensando che la classe genitore abbia solo bisogno di avere una proprietà Handler che indichi quale gestore abbia gestito l'evento alla fine, ma non sono sicuro del modo migliore per implementarlo. – RobinHood70

0

Penso che è necessario Task/Task<T>, soprattutto ContinueWith(Action<Task>) metodo e 4 proprietà: IsCanceled, IsCompleted, IsFaulted e Result.

1

Probabilmente userò il modello di strategia qui.

http://en.wikipedia.org/wiki/Strategy_pattern

Hai solo bisogno di passare delgates invece di intere classi. Se tutti i metodi utilizzano le stesse informazioni per l'elaborazione, questo potrebbe essere utile.

+0

Questa è anche una buona soluzione, anche se sto capendo correttamente, non avrebbe il comportamento che stavo cercando. – RobinHood70

+0

Sembra che il tuo modello strategico entri in gioco dopo tutto. :) Grazie! – RobinHood70

Problemi correlati