Classi di dati: getter e setter o design di metodi diversi

7

Ho cercato di progettare un'interfaccia per una classe di dati che sto scrivendo. Questa classe memorizza gli stili per i personaggi, ad esempio se il carattere è in grassetto, in corsivo o sottolineato. Ma anche la dimensione del font e la famiglia di font. Quindi ha diversi tipi di variabili membro. Il modo più semplice per implementarlo sarebbe quello di aggiungere getter e setter per ogni variabile membro, ma questo mi sembra sbagliato. Sembra molto più logico (e più OOP) chiamare style.format(BOLD, true) anziché style.setBold(true) . Quindi usare metodi logici invece di getter / setter.

Ma sto affrontando due problemi durante l'implementazione di questi metodi: avrei bisogno di una grande istruzione switch con tutte le variabili membro, dato che non è possibile accedere a una variabile dal contenuto di una stringa in C ++. Inoltre, non puoi sovraccaricare per tipo di ritorno, il che significa che non puoi scrivere un getter come style.getFormatting(BOLD) (so che ci sono alcuni trucchi per fare questo, ma questi non consentono parametri, di cui ovviamente avrei bisogno).

Tuttavia, se implementassi getter e setter, ci sono anche problemi. Dovrei duplicare un po 'di codice perché gli stili possono anche avere uno stile genitore, il che significa che i getter devono guardare non solo alle variabili membro di questo stile, ma anche alle variabili degli stili genitore.

Poiché non ero in grado di capire come farlo, ho deciso di fare una domanda un paio di settimane fa. Vedi Programmazione orientata agli oggetti: getter / setter o nomi logici . Ma in quella domanda non sottolineo che sarebbe solo un oggetto dati e che non sto facendo un motore di rendering di testo, motivo per cui una delle persone che ha risposto mi ha suggerito di porre un'altra domanda rendendo chiaro questo (perché il suo soluzione, il modello decoratore, non è adatto per il mio problema). Quindi, tieni presente che non sto creando il mio motore di rendering del testo, ma uso queste classi per archiviare i dati.

Poiché non sono ancora riuscito a trovare una soluzione a questo problema, mi piacerebbe fare ancora una volta questa domanda: come progetteresti una classe di stili come questa? E perché lo faresti?

    
posta Frog 09.09.2012 - 14:03
fonte

3 risposte

9

Parte 1

Questa è una buona domanda di design. Hai ragione nel rilevare l'odore del codice relativo a getter e setter. Generalmente indicano un problema di progettazione che espone i dettagli di implementazione del tuo oggetto.

Cerca di pensare in termini di ciò che i tuoi oggetti dovrebbero fare: Tell, Do not Ask:

Il tuo primo problema potrebbe essere che stai provando a progettare "classi di dati". Piuttosto che preoccuparsi dei dati (dettagli di implementazione), pensa alla funzionalità. Di nuovo, cosa dovrebbero fare i tuoi oggetti? Nel tuo caso, cosa vuoi fare con gli stili di carattere? Chi (riguardo al software) si preoccupa degli stili dei personaggi? Cosa devono fare?

Spero che questo ti possa iniziare. Lo sviluppo guidato dai test aiuta con questi tipi di problemi di progettazione. Ti costringe a pensare in termini di funzione e non di dati.

Al contrario, se tutto ciò di cui hai bisogno è un contenitore di dati, scrivi una classe struct in stile C e vai in città. Non lo consiglierei, il mantenimento sarà un $ @ #% #.

Buona fortuna!

Parte 2

Quello che vuoi è una semplice classe di dati - salta completamente i getter e setter, o vuoi creare un'astrazione indipendente dalla piattaforma che collochi una facciata (Modello di facciata) davanti al rendering e impostazione di stile. Fornisce semplicemente un'interfaccia per l'impostazione di stili e rendering. L'implementazione specifica della tua piattaforma fa il lavoro sporco (utilizzando NSTextView nel tuo esempio).

Il vantaggio della semplice classe di dati è che è inizialmente semplice da scrivere. Il suo svantaggio è che avrete difficoltà a evitare un gigantesco groviglio di dichiarazioni if-else. Ti mancherà anche un posto chiaro per farti chiamate di rendering specifiche della piattaforma che usano gli stili. Con l'aumentare della complessità del sistema, potresti trovare più difficile decidere dove andare i dettagli dell'implementazione.

La facciata è un approccio più astratto. I vantaggi sono che è più flessibile e può essere riutilizzato se si decide di effettuare il porting su un'altra piattaforma. I suoi svantaggi sono i tempi di sviluppo più iniziali.

L'interfaccia pubblica della facciata fornirà ciò che ti serve per impostare e rimuovere gli stili e avviare il rendering quando sarà il momento.

I dettagli su come si desidera impostare gli stili dipendono da te. Usa quello che mai il sistema si sente meglio. Semplice get ters e set ters o generico set e get che usa un dizionario internamente funziona anche (vedi boost ptree se stai usando C ++). Potresti anche prendere tutti gli stili (o predefiniti) al momento della costruzione. Potresti decidere di non esporre i mutatori a quel punto. La tua chiamata. Forse decidi che è importante che i dati guidino gli stili supportati e utilizzino una configurazione più un sistema di fabbrica (possiamo aggiungere più dettagli in seguito se questo è importante per te). In effetti diversi implementazioni della facciata potrebbero fornire diversi modi di affrontare il problema. Potresti prototipare alcuni e scegliere ciò che funziona meglio.

L'implementazione specifica per la piattaforma della tua astrazione di facciata utilizzerà il sistema di rendering specifico della piattaforma ( NSTextView nel tuo caso) e gli stili che hai impostato per effettuare le chiamate appropriate al sistema. Basta iniettare le classi specifiche della piattaforma in fase di costruzione (Dependency Injection), implementare il metodo render() e dovresti essere a posto.

Parte 3

Se la progettazione del sistema lo consente, puoi prendere tutti gli stili per un particolare elemento in fase di costruzione. Questo potrebbe consentire di evitare completamente getter e setter se scegli di rendere il tuo elemento immutabile. Avrai quindi un'astrazione semplice, pulita e possibilmente immutabile di fronte al tuo sistema di stili di carattere. Lo stato immutabile generalmente porta a un numero inferiore di bug, ma richiede di operare secondo la premessa che non è possibile cambiare le cose, volenti o nolenti.

Facendo un ulteriore passo avanti, un file di configurazione potrebbe definire le diverse impostazioni di stile che hai. Ancora una volta ciò richiederebbe una conoscenza preliminare degli stili che si stanno impostando (simile alla costruzione con gli stili di cui sopra). Dare il tipo di stile che stai cercando, ad esempio "titolo", potresti recuperare la configurazione per le intestazioni che specifica un carattere più grande e in grassetto.

Queste sono solo alcune idee fuori dalla mia testa. Senza ulteriori requisiti in termini di raccolta e utilizzo dei casi, sarà difficile diventare più specifici.

Spero che aiuti. Buona fortuna!

    
risposta data 09.09.2012 - 15:56
fonte
2

Sento odore di lista di attribuzione. Sono d'accordo che si dovrebbe impostare il formato e ottenere il formato, tranne che vorrei usare una lista. Un po 'di maschera anche se i tuoi attributi lo consentono. Altrimenti, mantieni una serie di oggetti formattatore che usano IOC per formattare il campo, se possibile. perdonami, non so c ++

Public abstract class IFormatter
{
.   public abstract void FormatText(TextField* fieldToFormat);
}

Public class BoldFormatter : IFormatter
{...}

Public class TextField
{
.   public void AddFormatter(IFormatter* formatterToAdd)
.   {...}

.   public IFormatter[] GetFormatters()
.   {...}

.   public void Render()
.   {
.       foreach(IFormatter formatter in formatters)
.       { formatter.FormatText(this); }
}
    
risposta data 10.09.2012 - 23:14
fonte
2

Se tutto ciò che fanno è memorizzare i dati, allora perché preoccuparsi di ogni tipo di getter e setter? Non ci sono invarianti da applicare, nessun motivo logico per controllare i dati e nessun motivo per elaborarli né impedire l'accesso. La ragione della classe per essere è "Memorizza dati". Quindi, memorizza alcuni dati e lascia perdere.

    
risposta data 10.09.2012 - 23:50
fonte

Leggi altre domande sui tag