Design e relazione tra un cursore e il suo oggetto di riferimento

0

Ho bisogno di implementare una classe Cursor per eseguire operazioni su un oggetto Document, che è implementato internamente sotto forma di un semplice elenco di righe. La classe Cursor deve avere metodi come muoversi attorno al documento, aggiungere linee, rimuovere linee, inserire testo in una determinata posizione ecc.

Il problema che ho è relativo ai dettagli del design. Per me, sembra che il cursore deve conoscere i dettagli di implementazione della classe indicata. In C ++, queste classi devono essere classi di amici, ma non mi piace per ovvi motivi (incapsulamento, ecc.). Non riesco a immaginare un'interfaccia per la classe Document che mantenga la sua implementazione privata che non vanifica lo scopo di una classe Cursor, cioè, finisco per avere l'interfaccia del Cursore nella classe Document stessa.

I dettagli sull'implementazione del documento sono fuori uso quando si implementa un cursore? In caso contrario, quale dovrebbe essere l'interfaccia del documento?

    
posta Stefano Borini 22.04.2014 - 22:16
fonte

3 risposte

1

Sembra che Cursor rappresenti una posizione in Document . La classe Document dovrebbe essere in definitiva responsabile di tutte le operazioni primitive come l'inserimento, l'eliminazione, l'acquisizione di testo e lo spostamento. Molte di queste operazioni richiedono una posizione come input e alcune restituiscono anche una posizione come output. Cursor potrebbe essere solo una classe dati concreta che contiene solo la posizione e il Document , in pratica una coppia. L'altro approccio è di rendere Cursor un'astrazione di prima classe. In questo caso la sua API rispecchierà solo quella di Document , e ogni metodo sarà solo un involucro sottile attorno al metodo corrispondente su Document , ma i metodi su Cursor ometteranno il parametro posizione poiché verranno riempiti con la posizione da Cursor . Lo schema di base è qualcosa come

cursor.someMethod(arg1, ...) = cursor.doc.someMethod(cursor.pos, arg1, ...)

tranne se il metodo Document restituisce una posizione, allora il metodo Cursor dovrebbe comprimerlo insieme al documento e restituire un cursore come

cursor.otherMethod(arg1, ...) = new Cursor(cursor.doc,
                                           cursor.doc.otherMethod(cursor.pos, arg1, ...))

Lo svantaggio di questo approccio è la piastra della caldaia sul lato dell'implementazione, ma rende la libreria molto più bella da usare sul lato client. Dal momento che il boilerplate richiesto è semplice e sistematico, potresti essere in grado di evitare di scriverlo manualmente generandolo o eseguendo la delega tramite chiamate riflessive se stai usando un linguaggio con capacità di riflessione decente o un preprocessore ragionevolmente potente.

Devi ancora decidere quale posizione è. Può essere solo un numero che rappresenta la posizione del carattere nell'intero documento (ad es. Emacs), una coppia che rappresenta la linea e la posizione sulla linea, o un puntatore in C / C ++ direttamente nel contenitore sottostante. Ti suggerirei di posizionare un membro su Document se la tua lingua lo supporta. In questo modo ogni implementazione di Document può fornire la propria definizione del tipo di posizione. Cursor tratta le posizioni come completamente astratte, le tiene semplicemente e le passa a Document metodi. solo Document si preoccupa di come sono implementati.

    
risposta data 28.04.2014 - 06:27
fonte
0

A mio parere, non ha senso fare di Document un'astrazione, ma usarla in una classe separata. Se intendi realizzare l'implementazione di Document private, allora Cursor fa parte dell'API pubblica di Document - perché non eliminare semplicemente l'intermediario e spostare questi metodi nella classe Document ?

    
risposta data 25.04.2014 - 18:18
fonte
0

Una soluzione è quella di far passare il cursore alle coordinate xey del documento finito e lasciare che il documento decida in quale riga si trova. Si potrebbe anche fare in modo che il curser chiami metodi separati o passi un parametro per dire il documento se si tratta di una richiesta per rimuovere una riga, inserire un testo, eliminare una riga, ext.

Per portare questa linea di pensiero ad un altro livello, potresti anche creare classi per le tue righe. Le righe e il documento implementerebbero entrambe una classe astratta dell'ascoltatore del mouse. Ciò consentirebbe al mouse di passare un evento click al documento per determinare la riga in cui si trova e passarlo alla riga per determinare la posizione del carattere sulla riga su cui si trovava l'evento.

    
risposta data 28.04.2014 - 06:27
fonte

Leggi altre domande sui tag