Decoratore che non chiama l'istanza decorata: è necessaria una progettazione alternativa

1

Supponiamo che disponga di un'interfaccia semplice per la traduzione di testo (codice di esempio in C #):

public interface ITranslationService
{
    string GetTranslation(string key, CultureInfo targetLanguage);
    // some other methods...
}

Una prima semplice implementazione di questa interfaccia esiste già e va semplicemente al database per ogni chiamata di metodo. Supponendo che un'interfaccia utente che viene tradotta all'avvio restituisca una chiamata al database per controllo.

Per migliorare questo, voglio aggiungere il seguente comportamento:

As soon as a request for one language comes in, fetch all translations from this language and cache them. All translation requests are served from the cache.

Ho pensato di implementare questo nuovo comportamento come decoratore, perché tutti gli altri metodi di quell'interfaccia implementati dal decoratore sarebbero stati delegati all'istanza decorata.
Tuttavia, l'implementazione di GetTranslation non userebbe GetTranslation dell'istanza decorata affatto per ottenere tutte le traduzioni di una certa lingua. Avrebbe generato una sua query sul database.
Questo rompe il modello decoratore, perché ogni funzionalità fornita dall'istanza decorata viene semplicemente saltata. Questo diventa un vero problema se ci sono altri decoratori coinvolti.

La mia comprensione è che un decoratore dovrebbe essere additivo. In questo caso, tuttavia, il decoratore sostituisce il comportamento dell'istanza decorata.

Non riesco davvero a pensare ad una bella soluzione per questo - come lo risolveresti? Tutto è permesso, anche un completo riprogettazione di ITranslationService stesso.

    
posta Daniel Hilgarth 25.06.2013 - 13:17
fonte

2 risposte

1

Mantieni ITranslationService , invece di implementare le chiamate direttamente alla cache o al database, invia a un oggetto IRepository che utilizza un elenco di IProvider s preferiti che forniscono l'accesso ai meccanismi di persistenza sottostanti.

Il primo, o generalmente "provider preferito", è un CacheProvider . Il secondo è il LocalDatabaseTranslationProvider primario. Immaginabile, potrebbe esserci un terzo o più fornitori. L'ultimo provider nell'elenco è il meno preferito, ma un provider di fallback affidabile. Ad esempio, si potrebbe prendere la forma di un servizio di traduzione di terzi. Sarebbe implementato come un servizio proxy di oggetti come RemotePartnerTranslationProvider .

Ogni provider implementerà un'interfaccia comune che consente alla strategia di differire, quindi indipendentemente dal fornitore scelto e indipendentemente da come ciascuno di essi fornisce letture e scritture, il repository agisce su ciascuna e riceve da ciascuna allo stesso modo. Il repository è responsabile della fornitura del coordinamento e della risoluzione dei conflitti tra i provider quando necessario.

Tra le altre preoccupazioni, potreste considerare un'interfaccia osservabile anche per ogni provider, per quando è necessario propagare / inviare lo stato / segnale tra tutti / la maggior parte dei provider dal repository, ad esempio per chiuderli o eliminarli correttamente durante la pulizia su / giù.

    
risposta data 25.06.2013 - 14:38
fonte
1

La fattibilità di molte delle opzioni possibili dipende da quanto è chiusa l'implementazione corrente dell'interfaccia ITranslationService .

  • Se l'implementazione corrente è completamente chiusa (classe finale, nessuna modifica sarà accettata), allora le tue uniche opzioni reali sono

    • Crea un'implementazione indipendente e indipendente dell'interfaccia
    • usa il tuo attuale approccio 'decoratore'. Questo può essere esteso per chiamare il metodo GetTranslation dell'oggetto decorato se la traduzione non è stata trovata nella cache.
  • Se l'implementazione corrente consente sottoclassi, puoi fornire la versione memorizzata nella cache come classe derivata

  • Se l'implementazione corrente è ancora aperta per la modifica, puoi cambiare l'implementazione di GetTranslation per utilizzare il modello di strategia , dove una strategia va sempre al database e l'altra utilizza il caching.
risposta data 25.06.2013 - 13:40
fonte

Leggi altre domande sui tag