Comprendere la programmazione orientata agli oggetti: perché è importante? [duplicare]

1

Ho appena iniziato a studiare le classi in C ++ e ho difficoltà a capire perché la programmazione orientata agli oggetti (OOP) sia utile. Capisco la sintassi, come usarli ecc.

Ma sono ancora confuso sul perché OOP sia vantaggioso. Ecco alcune specifiche con cui ho problemi:

  1. Variabili private. Qual è l'uso? Molte fonti mi dicono che impedisce agli estranei di modificare le variabili interne dell'oggetto, per proteggere gli "interni". Questo non ha senso per me perché qualcuno che non volesse cambiare la variabile chiama semplicemente le funzioni setter (mutatore) e lo cambia? Chiunque può aprire il file sorgente e chiamare il setter e modificare il valore della variabile. Come è questa "protezione"? Si è anche detto che rende più facile il debug perché invece di cercare ogni istanza della variabile "x", si sa che "x" è accessibile solo attraverso la classe. Quindi invece di ctrl + F "x" hai solo ctrl + F "memberFunction" ?? In che modo è più facile eseguire il debug?

  2. Ho letto da qualche parte che usare getter e setter è sbagliato. Anche se a volte inevitabile, è generalmente cattivo. Ho letto "Non chiedere le informazioni che ti servono per fare il lavoro, chiedi all'oggetto che ha le informazioni per fare il lavoro per te". Qualcuno può spiegare perché questo è importante?

  3. L'immagine grande. Non capisco perché l'implementazione degli oggetti sia più efficiente delle sole istruzioni if e chiamate di funzione .... anche quando ci sono funzioni negli oggetti. Gli oggetti non sembrano risparmiare un sacco di tempo in termini di programmazione. Cosa mi manca?

posta IanKZ 22.04.2014 - 04:50
fonte

3 risposte

2

Forse un esempio può aiutare a spiegare i vantaggi della programmazione orientata agli oggetti.

Considera una lista collegata, costituita da strutture di nodi contenenti alcuni dati e che punta ad altri nodi:

struct Node {
    Node* next;
    int data;
}

Assumi un elenco di questi (li ho nominati per comodità):

Node c{null, 4};
Node b{&c, 73};
Node a{&b, 42};
Node* list = &a;

Puoi usare questo elenco come segue:

std::cout << list->data; // prints 42
std::cout << list->next->data; // prints 4

Tutto va bene qui, ma immagina da qualche parte nel tuo programma che succede:

Node d{&a, 17};
list->next->next = &d;

Ora la lista è incasinata, è: [a, b, d, a, b, d, …] ; il nodo c è perso e l'elenco è diventato una ripetizione infinita.

1a

Per rispondere alla prima parte della parte 1 della tua domanda, quando Node::next è privato, l'assegnazione problematica list->next->next = &d; non può avvenire.

1b & 2

Dato un setter pubblico:

Nodo void :: setNext (Node * new_next) {        this- > next = new_next;    }

Come dici tu, chiunque può usare solo list->next->setNext(&d); . Questo porta alla risposta alla seconda parte della tua domanda: avere un setter setNext() è cattivo. Le liste dovrebbero avere operazioni di modifica come insert(value) , append(value) e remove(value) .

Questo è un esempio della regola generale: le classi dovrebbero avere operazioni che si adattano al significato e all'uso previsti, non a getter e setter per ogni campo che l'implementazione ha. Oppure la versione che leggi: "Non chiedere le informazioni che ti servono per fare il lavoro, chiedi all'oggetto che ha le informazioni per fare il lavoro per te."

3

La tua domanda, "Non capisco perché implementare oggetti sia più efficiente di solo se-istruzioni e chiamate di funzione", è difficile. Innanzitutto la parola "efficiente" può avere due significati:

  1. i programmi vengono eseguiti più velocemente e / o consumano meno risorse
  2. scrivere un programma richiede meno sforzo

Per il primo punto che esegue più velocemente o consuma meno risorse, sia i programmi orientati agli oggetti che i programmi che usano le istruzioni if e le chiamate di funzione possono essere efficienti in questo senso o molto inefficienti. Per alcuni problemi a pensarli in modo orientato agli oggetti, si ottiene una soluzione più elegante ed efficiente rispetto alle istruzioni if e alle chiamate di funzione. Per altri problemi, la programmazione orientata agli oggetti si intromette e causa un sovraccarico.

Sulla seconda interpretazione di "efficiente": scrivere un programma richiede meno sforzo.

  1. Poiché @JB_King afferma che l'orientamento all'oggetto aiuta a organizzare le cose che appartengono insieme.
  2. Una volta che hai la classe list, in altre parti del codice puoi pensare in termini di mantenimento di un elenco di "x" e invio di un elenco di "y", anziché manipolazioni di puntatori. Inoltre, quando si guarda la libreria standard C ++, la libreria runtime Java, Boost Collection , raccolte Commons , Google guava , e altri scoprirai che altri hanno già scritto delle classi List e che forse per il tuo problema di programmazione un elenco non è la migliore, ma qualche altro tipo di raccolta.
    Quindi una volta che hai (o qualcun altro ha) scritto un corso puoi riutilizzarlo e non devi scriverlo più. NOTA: ovviamente lo stesso vale per le buone librerie di funzioni, alla mia risposta manca una buona spiegazione del perché l'object oriented è meglio riusabile rispetto alle librerie funzionali.

Elaborazioni e nodi laterali

Anche se decidi che questa classe elenco richiede realmente un metodo setNext() -method, allora il metodo può avere vantaggi rispetto alla manipolazione diretta del Node::next -field. Il metodo può eseguire controlli aggiuntivi; per esempio:.

Node: setNext (Nodo * newNext) {        se (this- > next == null)        {            this- > next = newNext;        }        altro        {            lanciare un nuovo errore ();        }    }

Rendere privati i campi non impedisce a programmatori / codice malintenzionati di leggere e manipolare il campo; cioè.

class SecurityController {
private:
    std::string secretPassword;
};

e

struct SecurityController2 {
    std::string secretPassword;
}

sono entrambi ugualmente (in) sicuri.

Dichiarare le cose private (e altri metodi per nascondere i dettagli di implementazione) aiuta solo i programmatori che si comportano bene a creare un codice migliore.

L'inizializzazione

A volte l'inizializzazione di un oggetto è l'unica volta in cui è richiesto l'accesso diretto ai campi di un oggetto. Quindi puoi definire un costruttore che accetta e imposta il campo, ad esempio:

Node::Node(int value_) {
    this->value = value_;
}

Tuttavia, spesso esistono costruttori migliori che non richiedono che il chiamante fornisca valori. Ad esempio:

List::List() {
    …
}

per costruire un List vuoto e

List::List(std::iterator<int> start, std::iterator<int> end) {
    …
}

per creare un elenco contenente copie dei valori dell'intervallo STL di C ++ [inizio, fine >.

    
risposta data 22.04.2014 - 12:34
fonte
2
  1. Si noti che si presume che un setter esista sempre e possa essere modificato. In alcuni punti, il codice back-end sarà separato dal front-end e ci sono solo alcuni modi per contattare il back-end. In questo caso, le variabili private possono essere utilizzate per nascondere i dettagli interni di quelli che utilizzano il codice. Ciò è molto importante in quanto molto codice esisterà negli ambienti a più livelli in cui potrebbe esserci una piattaforma back-end separata dall'interfaccia utente front-end. Il debugging può essere più semplice perché si può cercare dove viene usata la variabile piuttosto che avere un codice spaghetti se le proprietà vengono utilizzate eccessivamente o violate.

  2. Questo si riferisce all'idea di quali metodi fa la classe e cosa può essere fatto al di fuori della classe. L'uso eccessivo di proprietà può portare a un sacco di duplicazione del codice che può causare problemi se si desidera modificare i dettagli interni della classe.

  3. Quanto è grande il più grande progetto di codifica che hai fatto? Hai programmato un sistema di carrello degli acquisti con utenti e prodotti? Senza classi, come terrò traccia di tutti i dati che qualcuno ha in un carrello? Come gestisci il fatto che i dati del database possono contenere relazioni meglio rappresentate come oggetti rispetto all'utilizzo di un gruppo di primitive che potrebbero complicarsi come se avessi liste per i nomi di prodotti, prezzi di prodotti e descrizioni, una sorta di una qualsiasi lista potrebbe far sì che anche gli altri vengano ordinati, altrimenti i dati vengono inseriti nell'ordine sbagliato.

risposta data 22.04.2014 - 05:17
fonte
2

Il codice che produci potrebbe essere consumato da terze parti. Poiché è il tuo codice, ti sembra strano dover nascondere i dettagli dell'implementazione attraverso proprietà e metodi privati. Quando date questo codice a qualcun altro, non hanno bisogno di sapere come funziona il vostro codice, invece hanno bisogno di sapere cosa fa.

Per esporre il bit "che cosa fa", usi i modificatori di accesso pubblico. Immagina un distributore automatico. Si rilascia una moneta, si seleziona un prodotto e la macchina ti offre una bevanda gassata. Hai davvero bisogno di sapere come funziona la macchina? Non ti interessa solo avere un prodotto dopo aver messo i soldi e aver premuto il pulsante.

Riguardo ai setter e ai getter - sì, puoi renderli pubblici. Non appena lo fai, esponi i dettagli di implementazione al consumatore. Immagina di avere tre proprietà private e un metodo chiamato "ServeDrink". È possibile scegliere di esporre tutte e tre le proprietà e un metodo tramite un modificatore di accesso pubblico. Tu dai questo a qualcun altro. Quella persona (consumatore) guarda la tua API, vede le proprietà pubbliche e inizia a usarle liberamente. Un mese dopo, decidi di cambiare il modo in cui funziona, c'è ancora una funzione per servire un drink, ma non vuoi più avere tre proprietà, ma inserisci una singola proprietà che aggrega le vecchie tre proprietà. Dacci questo al consumatore.

Il consumatore della tua API si trova ora di fronte a un problema, laddove ritiene che sia corretto utilizzare tre proprietà pubbliche, quando invece non è il caso. Detto questo, puoi provare a pensare a un consumatore come utente finale. Utilizzando la progettazione OO, si impostano limiti e limiti su come utilizzare l'API. Dichiari anche chiare responsabilità. Per esempio. se qualcosa è pubblico, intendi che il consumatore lo usi, e se è privato, che il consumatore non dovrebbe neppure accorgersene.

Prova a leggere questa storia link - è una divertente lettura comparativa di funzioni e registri OO.

    
risposta data 22.04.2014 - 11:25
fonte

Leggi altre domande sui tag