È questo uno schema? Delega / delega dell'interfaccia all'attuazione concreta esistente

4

Di tanto in tanto scrivo codice come questo quando voglio sostituire piccole parti di un'implementazione esistente:

public interface IFoo
{
    void Bar();
}

public class Foo : IFoo
{
    public void Bar()
    {
    }
}

public class ProxyFoo : IFoo
{
    private IFoo _Implementation;

    public ProxyFoo(IFoo implementation)
    {
        this._Implementation = implementation;
    }

    #region IFoo Members

    public void Bar()
    {
        this._Implementation.Bar();
    }

    #endregion
}

Questo è un esempio molto più piccolo rispetto ai casi reali in cui ho usato questo modello, ma se implementare un'interfaccia esistente o una classe astratta richiederebbe molto codice, la maggior parte dei quali è già scritta, ma ho bisogno di cambiare una piccola parte del comportamento, quindi userò questo modello.

Questo è un pattern o un pattern anti? Se sì, ha un nome e ci sono pro e contro ben noti a questo approccio?

C'è un modo migliore per ottenere lo stesso risultato? Riscrivere le interfacce e / o l'implementazione concreta normalmente non è un'opzione in quanto verrà fornita da una libreria di terze parti.

    
posta Ian Newson 12.06.2012 - 17:24
fonte

2 risposte

7

Sì, questo è un modello di decoratore e sicuramente ha il suo posto.

Il mio unico consiglio qui non sarebbe di chiamare la classe un proxy poichè alcune persone potrebbero associarlo con un schema di progettazione del proxy e diventa un po 'confuso. I proxy generalmente non cambiano il comportamento, ma piuttosto servono come una sorta di canale per l'oggetto reale. Questo canale può essere utilizzato per comunicazioni, autorizzazione, memorizzazione nella cache o controllo / pianificazione delle chiamate all'oggetto reale. In tutti i casi, il proxy non altera la "logica aziendale" effettiva del componente reale ma aggiunge alcune qualità "out-of-band".

Un decoratore implementerebbe la stessa interfaccia, ma potrebbe aggiungere o rimuovere il comportamento della logica aziendale che viene effettivamente esposto al client.

Ad esempio, lavoro in video e abbiamo oggetti di presentazione che espongono informazioni relative a dati live e registrati disponibili per una determinata sorgente video. In determinati luoghi vogliamo solo esporre video in diretta. In altri posti vogliamo esporre solo piccoli segmenti di video registrati. Invece di ricreare un intero oggetto di presentazione per ciascuno dei casi speciali, abbiamo utilizzato i decoratori "LiveOnlyPresentation" e "RecordedSegmentPresentation" per sovrascrivere una funzione ciascuno e limitare semplicemente ciò che il client può vedere.

    
risposta data 12.06.2012 - 17:40
fonte
2

Mi piace usare questo modello per il caching del repository: puoi separare la logica di caching dalla logica di accesso ai dati, ma poiché il contratto previsto è essenzialmente lo stesso (il metodo restituirà i dati richiesti, indipendentemente dal fatto che sia recuperato da una cache o dal repository sottostante), può tranquillamente implementare la stessa interfaccia.

public interface IPersonRepository
{
    Person GetById(int personId);
}
public class PersonRepositoryCache : IPersonRepository
{
    private static ConcurrentDictionary<int, Person> cacheById = 
       new ConcurrentDictionary<int, Person>();
    private IPersonRepository _repository;
    public PersonRepositoryCache(IPersonRepository repository)
    {
        _repository = repository;
    }
    public Person GetById(int personId)
    {
        return cacheById.GetOrAdd(personId, id => _repository.GetById(id));
    }
}

Dovrai essere cauto nel non utilizzare questo modello per modificare il comportamento contrattuale previsto dell'interfaccia, in quanto ciò violerebbe il Principio di sostituzione di Liskov. Cambia solo i dettagli dell'implementazione, assicurando al tempo stesso che le aspettative degli utenti sul comportamento della classe siano preservate.

Per ottenere il massimo da questo pattern, prendi in considerazione l'utilizzo di un contenitore IoC, in modo che le classi che utilizzano l'interfaccia non siano a conoscenza dei dettagli di implementazione.

Questo pattern è usato in modo efficace dalla programmazione orientata agli aspetti per aggiungere comportamenti come il logging alle chiamate ai metodi. Di nuovo, questi sono comportamenti che non alterano il comportamento contrattuale del metodo in questione.

Hat-tip to DXM per indicare che questo è chiamato Decorator Pattern.

    
risposta data 12.06.2012 - 17:51
fonte

Leggi altre domande sui tag