Evitare le insidie orientate agli oggetti, migrare dalla C, cosa ha funzionato per te?

12

Ho iniziato a programmare in linguaggi procedurali per un po 'di tempo e la mia prima reazione a un problema è iniziare a scomporlo in attività da eseguire piuttosto che considerare le diverse entità (oggetti) esistenti e le loro relazioni.

Ho frequentato un corso universitario in OOP e ho compreso i fondamenti di incapsulamento, astrazione dati, polimorfismo, modularità ed ereditarietà.

Ho letto link e link e guarderemo alcuni dei libri indicati in queste risposte.

Penso che molti dei miei progetti di dimensioni medio-grandi beneficeranno di un uso efficace di OOP, ma come novizio vorrei evitare lunghi errori comuni.

In base alle tue esperienze, quali sono queste insidie e quali sono i modi ragionevoli per aggirarle? Se potresti spiegare perché sono insidie e come il tuo suggerimento è efficace nell'affrontare il problema, sarebbe apprezzato.

Sto pensando sulla falsariga di qualcosa del tipo "È comune avere un discreto numero di metodi di osservatore e modificatore e usare variabili private o ci sono tecniche per consolidarli / ridurli?"

Non sono preoccupato di usare C ++ come linguaggio OO puro, se ci sono buone ragioni per mescolare i metodi. (Ricorda i motivi per usare GOTO, anche se con parsimonia.)

Grazie!

    
posta Stephen 21.06.2011 - 04:45
fonte

9 risposte

1

Volevo accettare una risposta a questa domanda, ma non ho potuto decidere una risposta per dare il segno di spunta. Come tale ho svalutato gli autori originali e ho creato questo come una risposta sommaria. Grazie a tutti quelli che hanno impiegato alcuni minuti, ho scoperto che l'intuizione che mi hai fornito mi ha dato una buona direzione e un po 'di sicurezza che non ero fuori dai binari.

@nightcracker

Well the first is the pitfall of exposing too much information. The default should be private, not public. After that comes too many getters/setters.

Ho sentito di aver osservato questo problema in azione in passato. I tuoi commenti mi hanno fatto anche ricordare che nascondendo le variabili sottostanti e la loro implementazione, sono libero di cambiare la loro implementazione senza distruggere tutto ciò che dipende da loro.

Dominic Gurto

Design the interface before you even start thinking about the implementation. Gene Bushuyev Interface design and implementation often go hand in hand in consecutive iterations until the final interface is crystallized.

Ho pensato che il commento di Dominic fosse un grande ideale a cui aspirare, ma penso che il commento di Gene colpisca davvero la realtà della situazione. Finora l'ho visto in azione ... e mi sento un po 'meglio che non è raro. Penso che mentre maturerò come programmatore mi proporrò a progetti più completi, ma in questo momento soffro ancora di un salto e di scrivere del codice-itis.

wantTheBest

I started slow, with small/medium-size procedural apps, and no mission-critical stuff at work. in the original procedural code, separate the data structures from the obsever/modifier code

Questo ha molto senso ... Mi piaceva l'idea di mantenere le cose funzionanti al lavoro, ma di rifattorizzare alcune cose non critiche con le classi.

JPM

One thing you definitely don't want to do is have a field that must be checked for consistency in the mutator, and leave it public

Da un po 'di tempo mi sono reso conto che questo è uno dei punti di forza dell'incapsulamento dei dati ... essere in grado di applicare la coerenza e per quella materia condizioni / intervalli / ecc.

Crazy Eddie

Someone thinking that they should stick to the OO paradigm and treat the others on the order of the goto statement in levels of immorality are really missing out by not looking at this paradigm. The metaprogramming capacity of templates is also quite impressive.

Originariamente mi mancava molto nella risposta di Crazy Eddie, penso perché non avevo letto su alcuni degli argomenti menzionati ... come la metaprogrammazione. Penso che il grande messaggio nel post di CE fosse che il C ++ è una tale miscela di capacità e stili che ognuno dovrebbe essere usato al loro miglior potenziale ... incluso imperativo se questo è ciò che ha un senso.

Quindi di nuovo, grazie a tutti quelli che hanno risposto!

    
risposta data 26.06.2011 - 02:02
fonte
10

Una cosa importante che ho imparato è progettare classi dall'esterno dentro. Progettare l'interfaccia prima ancora di iniziare a pensare all'implementazione. Questo renderà la classe molto, molto più intuitiva per i tuoi utenti (quelli che usano la classe) piuttosto che scrivere gli algoritmi sottostanti e costruire la classe, e scrivere nuove funzioni dei membri pubblici quando sono necessarie.

    
risposta data 21.06.2011 - 04:50
fonte
9

Bene, il primo è il rischio di esporre troppe informazioni. L'impostazione predefinita dovrebbe essere private , non public .

Dopo di ciò arrivano troppi getter / setter. Diciamo che ho un membro dei dati. veramente ho bisogno di questi dati in un'altra classe? Ok, fai un getter. realmente, davvero devo modificare questi dati durante la vita dell'oggetto? Quindi fai un setter.

La maggior parte dei programmatori principianti ha l'impostazione predefinita per creare un getter / setter per ogni membro dei dati. Questo ingombra interfacce e sono spesso scelte di progettazione sbagliate.

    
risposta data 21.06.2011 - 04:48
fonte
2

Quando ho attraversato quella voragine ho optato per il seguente approccio:

0) Ho iniziato lentamente, con app procedurali di piccole / medie dimensioni e nessuna roba mission-critical al lavoro.

1) una semplice mappatura di 1 ° passaggio su come scriverei il programma da zero in stile OO - la cosa più importante per me in quel momento, e questo è soggettivo - era di capire tutte le classi base. Il mio obiettivo era incapsulare il più possibile nelle classi base. Metodi virtuali puri per tutto ciò che è possibile nelle classi base.

2) Quindi il passo successivo è stato creare le derivazioni.

3) il passo finale era - nel codice procedurale originale, separare le strutture dati dal codice modificatore / obsever. Quindi utilizzare i dati che nascondono e mappare tutti i dati comuni nelle classi base e nelle sottoclassi sono passati i dati che non erano comuni in tutto il programma. E lo stesso trattamento per il codice procedurale di osservatore / modificatore - tutte le logiche "usate ovunque" sono entrate nelle classi base. E visualizzare / modificare la logica che ha agito solo su un sottoinsieme dei dati è andato nelle classi derivate.

Questo è soggettivo ma è VELOCE, se conosci bene il codice procedurale e le strutture dati. Un errore in una revisione del codice si verifica quando un bit di dati o logica non viene visualizzato nelle classi base ma viene utilizzato ovunque.

    
risposta data 21.06.2011 - 04:58
fonte
2

Dai un'occhiata ad altri progetti di successo che utilizzano OOP per avere un senso di buon stile. Ti consiglio di consultare Qt , un progetto che cerco sempre quando faccio le mie decisioni sul design.

    
risposta data 21.06.2011 - 05:04
fonte
1

A seconda di chi si parla, tutti i dati in OOP dovrebbero essere privati o protetti e disponibili solo tramite accessors e mutator. In generale, penso che sia una buona pratica, ma ci sono occasioni in cui divergo da questa norma. Ad esempio, se si ha una classe (in Java, diciamo) il cui unico scopo è quello di raggruppare alcune parti di dati in un'unità logica, è opportuno lasciare pubblici i campi. Se è una capsula immutabile, basta contrassegnarli finali e inizializzarli nel costruttore. Questo riduce la classe (in questo caso) a poco più di una struct (infatti, usando C ++, dovresti chiamare questa struct. Funziona proprio come una classe, ma la visibilità predefinita è pubblica, e l'intenzione è più chiara), ma Penso che scoprirai che usarlo è molto più comodo in questi casi.

Una cosa che non vuoi fare è avere un campo che deve essere controllato per la coerenza nel mutatore e lasciarlo pubblico.

    
risposta data 21.06.2011 - 04:53
fonte
1

I modelli di implementazione di Kent Beck Book sono un'ottima base su come utilizzare, non abusare, meccanismi orientati agli oggetti.

    
risposta data 21.06.2011 - 06:28
fonte
1

Non sono preoccupato di usare C ++ come puro linguaggio OO, se ci sono buone ragioni per mescolare i metodi. (Ricorda i motivi per usare GOTO, anche se con parsimonia.)

Non pensavo davvero di avere molto da offrire alla conversazione fino a quando non ho visto questo bit. Non sono d'accordo con il sentimento. OOP è solo uno dei paradigmi che possono e devono essere utilizzati in C ++. Francamente, a mio parere non è una delle sue caratteristiche più forti.

Da un punto di vista OO penso che il C ++ sia effettivamente un po 'corto. L'idea di avere funzioni non virtuali, per esempio, è un segno di spunta a riguardo. Ho avuto discussioni con coloro che non sono d'accordo con me, ma i membri non virtuali non si adattano al paradigma per quanto mi riguarda. Il polimorfismo è un componente chiave per OO e le classi con funzioni non virtuali non sono polimorfiche in senso OO. Quindi, come linguaggio OO, penso che il C ++ sia effettivamente piuttosto debole rispetto a linguaggi come Java o Objective-C.

La programmazione generica d'altra parte, C ++ ha questo piuttosto buono. Ho sentito dire che ci sono linguaggi migliori anche per questo, ma la combinazione di oggetti e funzioni generiche è piuttosto potente ed espressiva. Inoltre può essere dannatamente veloce sia nei tempi di programmazione che nei tempi di elaborazione. È proprio in quest'area che penso che il C ++ brilli anche se, ammettiamolo, potrebbe essere migliore (supporto linguistico per concetti ad esempio). Qualcuno che pensa di doversi attenersi al paradigma OO e trattare gli altri sull'ordine dell'istruzione goto in livelli di immoralità si sta davvero perdendo non guardando questo paradigma.

Anche la capacità di metaprogrammazione dei modelli è abbastanza impressionante. Controlla la libreria Boost.Units ad esempio. Questa libreria fornisce supporto per tipo per quantità dimensionali. Ho fatto ampio uso di questa libreria nella società di ingegneria per cui lavoro attualmente. Fornisce solo un feedback molto più immediato per un aspetto del programmatore possibile, o anche per l'errore di specifica. È impossibile compilare un programma che utilizza una formula in cui entrambi i lati dell'operatore '=' non sono equivalenti dimensionalmente senza il casting esplicito. Personalmente non ho esperienza con nessun altro linguaggio in cui ciò sia possibile, e certamente non con uno che abbia anche la potenza e la velocità del C ++.

La metaprogrammazione è un paradigma puramente funzionale.

Quindi, davvero, penso che stai già entrando in C ++ con alcuni malintesi sfortunati. Gli altri paradigmi oltre a OO non devono essere evitati, devono essere LEVERAGED. Usa il paradigma che è naturale per l'aspetto del problema su cui stai lavorando. Non forzare oggetti su ciò che essenzialmente non è un problema soggetto a oggetti. Per quanto mi riguarda, OO non è nemmeno la metà della storia di C ++.

    
risposta data 21.06.2011 - 07:33
fonte
0

Il più grande trabocchetto è la convinzione che OOP sia un proiettile d'argento, o il "paradigma unico perfetto".

    
risposta data 26.06.2011 - 02:06
fonte

Leggi altre domande sui tag