Originariamente inviato da Neptune
Effettivamente avevo sentito parlare di questo appproccio "inverso".

Cioè la superclasse sarà "ordinamento", che però deve avere almeno in maniera "virtuale" delle classi di leggi e scrivi,
I metodi leggi e scrivi. In linea di massima comunque sarebbe bene che i metodi leggi e scrivi siano in una classe ancora più su nella gerarchia, in maniera tale che se la classe contenitore vuole ereditare da due classi-algoritmo non abbia casini perché entrambe le classi vogliono i "loro" leggi e scrivi. L'idea, un po' più espansa per includere anche un altro algoritmo, sarebbe
codice:
+--------------------+                              +------------------------+
| RandomAccessible   | < indica un container        | SequentiallyAccessible | < indica un container
+--------------------+   ad accesso casuale         +------------------------+   ad accesso sequenziale
| virtual leggi = 0  |                              | virtual gonext = 0     |
| virtual scrivi = 0 |                              | virtual goprev = 0     |
+--------------------+                              | virtual cur = 0        |
         ||               indica un container       +------------------------+                 Indica un container in cui
         ||               ordinabile                            ||     \\                      si può effettuare una ricerca
         ||                  V                                  ||      \\                       V
         ||               +--------------------+                ||       \\____________      +--------------------+
         ||               | Sortable           |                ||        \------------\     | Searchable         |
         ||               +--------------------+                ||                     \\    +--------------------+
         ||               | virtual ordina = 0 |                ||                      \\   | virtual cerca = 0  |
         ||               +--------------------+                ||   supponiamo che lo   \\  +--------------------+
         ||                      //\\                           ||   strangesort sia      \\          ||
         ||     ________________//  \\____________________      ||   molto efficiente con  \\         ||  
         ||    /----------------/    \--------------------\     ||   container sequenziali  \\        ||  
         ||   //                                          \\    ||        V                  \\       ||  
+--------------------+                              +-----------------------------+          +---------------------+
| QuickSortable      | <-- il quicksort             | StrangeSortable             |          | LinearSearchable    | 
+--------------------+     necessita di un          +-----------------------------+          +---------------------+      
| ordina             |     accesso casuale          | ordina (usa i metodi        |          | cerca (usa i metodi |      
| (usa leggi/scrivi) |                              | di SequentiallyAccessible   |          | di Seq.Accessible   |
+--------------------+                              | per accedere agli elementi) |          +---------------------+
         ||                                         +-----------------------------+                 //  A  
         ||    _________________________________________________||________________________________ //   \\per una ricerca lineare
         ||   /-------------------------------------------------||--- -----------------------------/      basta poter leggere gli
+-----------------------+                                       ||  //                                    elementi sequenzialmente
| Vector                |                           +-----------------------------+
+-----------------------+ < un vettore è            | DoublyLinkedList            |  < su una lista si possono applicare
| leggi (implementata)  |   sia ad accesso          +-----------------------------+    algoritmi che operano ad accesso
| scrivi (implementata) |   casuale che             | gonext (implementata)       |    sequenziale
| gonext (implementata) |   sequenziale             | goprev (implementata)       |
| goprev (implementata) |                           | cur (implementata)          |
| cur (implementata)    |                           +-----------------------------+
+-----------------------+

Sia su Vector che su DoublyLinkedList si possono richiamare ordina e cerca; il
primo metodo (virtuale in Sortable) è implementato in maniera differente: su
Vector richiama QuickSortable::ordina, che usa Vector::leggi e Vector::scrivi
tramite i metodi virtuali di RandomAccessible, mentre su DoublyLinkedList usa
StrangeSortable::ordina, che usa i metodi virtuali di SequentiallyAccessible
implementati in DoublyLinkedList).
Al contrario, cerca è sempre lo stesso (dichiarato come virtuale in Searchable,
implementato in LinearSearchable), che usa i metodi virtuali di Sequentially-
Accessible. Questi tuttavia sono implementati in maniera differente in
DoublyLinkedList (dove useranno i soliti sistemi della lista) e in Vector (dove
saranno un semplice incremento/decremento di un puntatore).
(perdona l'ASCII-art, ma non ho molto di meglio sottomano )
che poi andranno ad essere implementate materialmente nelle classi figlio e varieranno da struttura dati a struttura dati, giusto?
Esatto.
Cioè io dichiaro ordinamento come superclasse che usa poi un'altra classe per leggere e scrivere.
Esatto, la classe derivata definisce effettivamente i metodi leggi e scrivi (il trucco magico della superclasse virtuale consente di far usare agli algoritmi metodi che al loro livello della gerarchia non sono ancora definiti).
Ma con la classe virtuale, ai fini dell'astrazione, come posso fare a dire in un secondo momento che quel leggi e scrivi si riferiscono ad una lista anzichè ad un array anzichè a non so che altro?
Sì, anche se in realtà una lista difficilmente avrà dei leggi e scrivi uguali ad un vettore anche come interfaccia, dato che in una lista ci si può muovere avanti e indietro, mentre saltare ad un determinato indice è molto dispendioso, per cui, come nell'esempio sopra, tendenzialmente ci sarà un'altra superclasse con i metodi che sono "tipici" della lista (spostati avanti, indietro, elemento corrente) che verranno sfruttati dagli algoritmi ottimizzati in maniera particolare per questa situazione.
Nota che se ad un algoritmo bastano requisiti minimi (potersi muovere semplicemente avanti, come capita per una ricerca lineare) nulla impedisce che si possano applicare anche a container più "evoluti": le operazioni di base di una lista si possono implementare anche su un vettore, per cui se noi abbiamo una superclasse di ricerca lineare che eredita dalla superclasse che definisce gonext, goprev e cur, nulla ci impedisce di far ereditare la classe Vector da questa, implementando gonext, goprev e cur in maniera adeguata per i vettori (cosa estremamente semplice). Così, come nell'esempio, possiamo applicare sia QuickSortable che LinearSearchable ad un Vector.
Se scrivessi superclasse Ordinamento che usa i metodi Matrice::Leggi e Matrice::Scrivi, poi dopo, dovrò a forza usare una matrice. Se volessi invece usare dei metodi "generali" e poi solo in un secondo momento dichiararli come "lettura di matrici" o di "liste"? O addirittura scegliere se si avvera una determinata condizione usa una lista, altrimenti una matrice?
Guarda l'esempio.
Per capire un pò meglio all'atto pratico la cosa, sempre che non ti è troppo dispersivo in termini di tempo, ti andrebbe di dichiararmi in maniera pratica una classe ordinamento, che usa i metodi di una classe virtuale leggi e scrivi, e poi dichiarati in un secondo momento questa classe virtuale in modo da poter decidere se usare una lista o un array? Giusto perchè magari con un pò di codice alla mano su cui discutere magari mi riesce meglio capire
È più o meno quello che ho fatto nell'esempio, senza scrivere codice ma delineandone la struttura, così come ho fatto nel post ancora prima nei vari esempi. Tieni conto che non è una grande idea usare un algoritmo su container non adatti ad esso, ad esempio applicare una ricerca binaria su una lista è assolutamente senza senso (saltare avanti e indietro "a balzelloni" su una lista non è efficiente), mentre, come detto, algoritmi che hanno requisiti "minimi" (ricerca lineare) si possono applicare più o meno dovunque.