Come gestire le affinità?

3

Supponiamo di avere una classe astratta che ha diverse classi concrete che le interfacce pubblicano un'informazione sotto diverse forme equivalenti, con la differenza che ogni classe ha una forma preferita che può essere consultati a costo zero consultando gli altri potrebbe richiedere a calcolo che richiede tempo. Come implementare una strategia selezionando un algoritmo basato su questa "affinità" di una classe per una informazione formare?

Esempio

L'esempio originale è un esempio complicato di molto specializzato campo, quindi farò del mio meglio per capire un esempio che sarà familiare alla maggior parte dei programmatori.

Supponiamo di avere una classe astratta che rappresenta i dispositivi I / O che ha due sottoclassi concrete, una per i dispositivi basati su char e una per dispositivi basati su blocchi. Ogni classe fornisce accesso basato su blocchi e accesso basato su cahr, ma ogni classe ha affinità con uno di questi metodi: l'accesso basato su blocchi è preferito per i dispositivi basati su blocchi, ecc. Diciamo, vogliamo implementare una procedura di copia, in modo che, se la fonte e i dispositivi di destinazione sono basati su blocchi, quindi viene eseguita la copia blocco per blocco, in tutti gli altri casi è un approccio char-by-char preferito.

Discussione

Supponiamo ora di avere non solo dispositivi I / O, ma diverse classi astratte offre accesso a diversi metodi logicamente equivalenti, ma di chi l'implementazione differisce notevolmente per la precisione, mostrando quindi una maggiore affinità con un metodo rispetto agli altri.

Vogliamo implementare una strategia lavorando su un insieme di tali classi e selezionando un algoritmo prendendo le affinità di questi classi in considerazione.

A causa della complessità combinatoria portata dall'aggregato, il il modello di visitatore non sembra utile qui.

Domanda

Come ogni classe concreta può esporre la propria affinità con l'una o l'altra metodo di accesso in un modo che è utile per un prelievo di componenti strategici un algoritmo adatto a queste affinità? La combinatoria produce a un gran numero di combinazioni di affinità e la strategia ha solo bisogno considerare alcuni "casi fortunati" e utilizzare un algoritmo generico da gestire la stragrande maggioranza delle combinazioni.

    
posta user40989 03.02.2014 - 13:05
fonte

4 risposte

2

Questo tipo di problema è familiare, ma non penso che esista un'unica soluzione canonica. I due che vengono subito in mente sono la negoziazione e la cosiddetta inversione di controllo.

La negoziazione è comunemente usata per scegliere tra i protocolli. Il tuo modem 56K o fax lo fa. Così fa il tuo server di posta. In sostanza, un servizio deve dire all'altro: "Posso fare A, B, C, quale preferiresti?" Il secondo servizio rende la scelta ed è vincolante. In scenari più complessi possono esserci più cicli di negoziazione. Quindi si basa su un canale di negoziazione specifico.

Ci sono pochi riferimenti utili sulla negoziazione del protocollo. Prova questo: link per alcune idee.

IOC in questo contesto significa che esiste un arbitro con un insieme di regole, che chiamerà una fabbrica su ciascun servizio per restituire un'implementazione concreta specifica e quindi le collegherà tra loro. Questa è una soluzione ampiamente utilizzata in molti contesti.

Questa è una tecnica ben nota, ampiamente scritta. Questo è un buon punto di partenza: link .

    
risposta data 03.02.2014 - 15:15
fonte
2

Non penso che esista uno schema per questa specifica implementazione. Il più vicino che si può ottenere sarebbe il modello di fabbrica con alcune modifiche. Lo schema di fabbrica perché il chiamante non dovrebbe sapere come viene implementato per la maggior parte, solo che viene eseguito.

Tuttavia, rimane ancora il problema di selezionare l'algoritmo corretto. Se hai pochi algoritmi, chiama semplicemente l'algoritmo per nome come @Lessat suggerito nella sua risposta. Altrimenti, il modo in cui lo farei sarebbe che tutte queste classi di algoritmi derivino da un'interfaccia che oltre a "eseguire" per avviare l'algoritmo, un metodo chiamato "isSupported" che prende come parametro un enumeratore definito nella tua fabbrica . Questo enumeratore elencerebbe i prerequisiti che devono essere presenti o che devono essere veri. Ad esempio, se si desidera eseguire il processo in modo asincrono, Asincrono sarebbe un tale enumeratore. Ogni implementazione restituirebbe true solo se supportata.

Creerei un altro metodo "ratePriority" che accetta come parametro un enumeratore definito nel factory che determina la priorità dell'algoritmo e restituisce un numero compreso tra 0 e 10 (10 è il migliore). Per priorità, voglio dire, se stessimo parlando di ordinare una lista, le priorità per me sarebbero, WorksBestAlreadySorted o WorksBestRandom o RequiresLittleMemory , ecc.

Quando si chiama la fabbrica, si passa una serie di funzionalità di supporto e una serie di priorità. La tua fabbrica quindi, uno per uno, eliminerà tutti gli algoritmi che non supportano tutte le tue funzionalità di supporto. Supponendo di avere più di un algoritmo rimasto, si determina il migliore calcolando il punteggio di ciascun algoritmo chiamando ratePriority su ciascuna priorità e si seleziona il più alto.

In questo modo, il chiamante deve solo preoccuparsi di supportare funzionalità e priorità di ciascun algoritmo e non su come viene eseguita l'implementazione effettiva. Anziché restituire un'istanza all'implementazione, è possibile chiamare direttamente execute su tale implementazione e restituire i risultati a tale chiamata.

Spero che ti aiuti!

Modifica: se i parametri di questi algoritmi cambiano, è possibile accettare i mapping di coppie valore-chiave che verrebbero quindi passati all'algoritmo stesso. La fabbrica non dovrebbe preoccuparsi di come chiamarla. Tuttavia, il chiamante non penserebbe che ci sia un modo per aggirare questo problema se quei parametri sono ciò che è richiesto.

    
risposta data 03.02.2014 - 13:52
fonte
1

Supponendo che il metodo ad alto costo abbia la stessa firma del metodo a basso costo. Dovrebbe essere possibile introdurre un "preferedMethod ()" che ha anche la firma prima menzionata ed è in ogni classe implementata per delegare al metodo a basso costo.

void lowCostMethod( args ...){
    //Implementation
}

void highCostMethod( args ...){
    //Implementation
}

void preferedMethod( args ...){
   lowCostMethod(args)
}
    
risposta data 03.02.2014 - 13:42
fonte
0

Basta aggiungere un metodo alla classe base per ottenere il metodo di trasporto preferito.

TransportEnum getPreferredTransport()

Ogni sottoclasse può restituire qualunque cosa sia e dato che la classe base conosce già tutti i possibili trasporti, dal momento che fornisce un'interfaccia diversa per ognuno di loro, non stai facendo del male all'astrazione.

    
risposta data 04.02.2014 - 16:13
fonte

Leggi altre domande sui tag