Come faccio a uscire dall'abitudine della programmazione procedurale e della programmazione orientata agli oggetti?

Spero di ricevere alcuni consigli per aiutarmi a uscire da quello che considero dopo tutti questi anni una brutta abitudine alla programmazione procedurale. Ogni volta che provo a fare un progetto in OOP, alla fine, finisco per tornare alla procedura. Immagino di non essere completamente convinto con OOP (anche se penso di aver sentito tutto bene!).

Quindi credo che each buon esempio pratico di attività di programmazione comuni che spesso svolgo come authentication / gestione degli utenti, analisi dei dati, CMS / Blogging / eComs sono il genere di cose che faccio spesso, eppure non sono stato in grado di get il mio gira intorno a come eseguirli in modalità OOP e lontano da procedurali, soprattutto perché i sisthemes che costruisco tendono a funzionare e funzionano bene.

Una cosa che posso vedere come una rovina per il mio sviluppo, è che io riuso il mio codice spesso, e spesso ha bisogno di più riscritture e miglioramenti, ma a volte lo considero una naturale evoluzione del mio sviluppo software.

Eppure voglio cambiare! Ai miei colleghi programmatori, aiuto 🙂 qualche consiglio su come posso uscire da questa ctriggers habbit?

    Che senso ha usare la programmazione orientata agli oggetti quando non riesci a trovare buone ragioni o motivazioni per farlo?

    Devi essere motivato dalla necessità di concepire e manipolare le idee come oggetti. Ci sono persone che sentono il bisogno di essere percettivi di concetti, flussi o funzioni piuttosto che oggetti e sono quindi motivati ​​verso una programmazione orientata verso concetti, idee o stream funzionale.

    Circa 13 anni fa, passai al c ++ da c semplicemente perché c'erano idee di cui avevo bisogno ma c non funzionava facilmente. In breve, il mio bisogno ha motivato la mia programmazione orientata agli oggetti.

    La mentalità orientata agli oggetti

    Innanzitutto, hai byte, caratteri, numbers interi e float.

    Quindi il tuo programma inizia a essere ingombra di tutti i tipi di variables, locali e statiche. Quindi decidi di raggrupparli in strutture perché hai capito che tutte le variables che vengono comunemente passate.

    Conglomerazione di dati

    Quindi, come le informazioni sulla printingnte dovrebbero avere tutte le sue variables racchiuse nella struttura della printingnte:

    {id, name, location, impactType(laser|inkjet|ribbon), manufacturer, networkAddr}, etc. 

    Così ora, quando chiami function dopo function su informazioni sulla printingnte, non hai funzioni con un lungo elenco di argomenti o una vasta raccolta di variables statiche con enormi possibilità di cross-talk.

    Incorporazione di informazioni

    Ma il conglomerato dei dati non è abbastanza buono. Devo ancora dipendere da un sacco di funzioni per elaborare i dati. Pertanto, ho avuto un'idea intelligente o incorporando i puntatori di function nella struttura della printingnte.

     {id, name, location, impactType(laser|inkjet|ribbon), manufacturer, networkAddr, *print(struct printer), *clean(struct printer) } 

    I dati si trasformano in informazioni quando i dati contengono i processi su come trattare / percepire i dati.

    Quantizzazione delle informazioni

    Ora le printingnti laser, a nastro e a getto d'inchiostro non hanno tutte lo stesso set di informazioni, ma tutte hanno un insieme di denominatori (LCD) più comune nelle informazioni:

    Informazioni comuni a qualsiasi printingnte: id, nome, posizione, ecc

    Informazioni trovate solo nelle printingnti a nastro: usati, nastri (tessuto | cellophane), colors, ecc

    Informazioni trovate solo a getto d'inchiostro: cartucce d'inchiostro, ecc

    Informazioni trovate solo su laser: …

    Per me e molte coorti orientate agli oggetti, preferiamo quantizzare tutte le informazioni comuni in un unico incapsulamento di informazioni, piuttosto che definire una struttura / incapsulamento separato per each tipo di printingnte.

    Quindi, preferiamo utilizzare un framework che gestisca tutte le funzioni di riferimento per each tipo di printingnte perché non tutte le printingnti vengono printingte o vengono pulite allo stesso modo.

    Quindi la tua preferenza / motivazione orientata lontano dagli oggetti ti sta dicendo che la tua vita di programmazione è più facile se non usi gli oggetti? Che preferisci gestire tutte quelle complessità strutturali da solo. Non devi aver scritto abbastanza software per sentirti in quel modo.

    La necessità della pigrizia

    Alcuni dicono: la necessità è la madre della creatività. (così come, l'amore per il denaro è la radice del male).

    Ma per me e le mie coorti – la pigrizia di fronte alla necessità sono i genitori della creatività. (così come la mancanza di denaro è l'altro genitore del male).

    Pertanto, ti esorto ad adottare un atteggiamento pigro verso la programmazione in modo che il principio del path più breve possa dare un calcio alla tua vita e troverai, ma non avrai altra scelta che laurearti per orientarti verso la programmazione con gli oggetti.

    Passaggio 1. Leggere un buon libro di templates di progettazione. http://www.oodesign.com/

    Passaggio 2. Scegli qualcosa che già conosci e rielaboralo da una prospettiva OO. Questo è l'approccio Code Dojo. Prendi un problema che già comprendi e definisci le classi dell'object.

    L'ho fatto e ho scritto quello che ho fatto.

    Vedi http://homepage.mac.com/s_lott/books/oodesign.html#book-oodesign

    Puoi fare la stessa serie di esercizi per get il massimo dal design e dal codice OO.

    La mentalità di OO si basa su principi che si trovano ad un livello molto più basilare rispetto ai templates di progettazione. I templates di design sono in qualche modo alla moda in questi giorni (e lo sono stati per un po '), e sono utili, ma sono solo uno strato in più che puoi mettere su cose di base che devi assolutamente imparare e padroneggiare se vuoi fare OO correttamente . In altre parole: puoi fare OO perfettamente senza schemi di progettazione. In effetti, molti di noi hanno fatto OO ben prima che la frase "templates di progettazione" fosse stata coniata.

    Ora, ci sono cose di cui non puoi fare a less. Ti suggerisco di iniziare alle basi. Leggere e comprendere "Costruzione di software orientata agli oggetti" Seconda edizione di Bertrand Meyer . È probabilmente il miglior libro sulla programmazione OO in giro, sia in width che in profondità. Questo è se sei interessato alla programmazione .

    Innanzitutto, congratulazioni per l'adozione di misure per imparare qualcosa di nuovo! Odio quando gli sviluppatori decidono di non evolversi con la tecnologia.

    Per quanto riguarda il passaggio da programmazione procedurale a OOP, direi che una cosa che puoi fare è prendere un'app esistente (come altri hanno menzionato) e, prima ancora di aprire un editor di text, sederti e pensare a come each aspetto di l'applicazione verrebbe convertita. Ho scoperto che più della metà della programmazione OO sta definendo gli oggetti concettuali nella tua mente.

    Di nuovo, sarò d'accordo con le raccomandazioni di tutti sui templates di design. Nello specifico, vorrei esaminare il pattern MVC (Model-View-Controller) in quanto questo potrebbe essere il più facile da capire. Hai già scritto il codice, quindi dovresti essere in grado di esaminare le tue applicazioni esistenti e iniziare a inserire each parte nelle categorie M, V o C.

    Buona fortuna e buon divertimento!

    Ci sono già parecchie risposte su where trovare informazioni sulla programmazione in un modo orientato agli oggetti. In effetti, ci sono molti grandi libri là fuori che definiranno i concetti di base, tuttavia penso che la domanda fosse più su come "attenerci ad essa" attraverso lo sviluppo di qualcuno nuovo del metodo.

    Tra i molti concetti in programmazione orientata agli oggetti, quello principale che ti terrà in pista come un nuovo arrivato è l'incapsulamento. La mia class sa come prendersi cura di se stessa? La mia class ha un comportmento? Se così non fosse, allora non hai una class, hai una struttura e probabilmente scriverà un sacco di procedure per cambiare il suo stato (come si dice, "sei tornato a scrivere C in Java") . La mia class espone solo methods pubblicamente necessari per il suo utilizzo? Queste domande potrebbero non essere approfondite ma forse considerare questo esperimento mentale durante la progettazione delle tue lezioni: cosa accadrebbe se ognuna delle classi della tua applicazione wheresse essere sviluppata e gestita da uno sviluppatore diverso su Internet e le classi wheressero interagire tra loro la networking. Ogni sviluppatore sarebbe d'accordo sul fatto che la class che stanno scrivendo e mantenendo aderisce al principio di responsabilità unica e quindi essere felici di non mantenere quello che dovrebbe essere il codice di qualcuno?

    Per quanto riguarda il design delle interfacce di class, considera di scrivere tutto il codice che utilizza prima le tue classi. Non preoccuparti di cosa deve ancora accadere al metallo. Dovresti essere in grado di estirpare l'integer programma in termini di relazioni di class prima di scrivere i tuoi primi dettagli sull'implementazione. Se non è ansible farlo senza bit di twiddling o rendendo pubblica una variabile, è ora di tornare al diagramma delle relazioni di class e vedere se manchi un'astrazione. In altre parole, usa il tuo codice prima di scrivere il tuo codice. Fatelo per primo e potreste essere sorpresi di quanto risulteranno puliti il ​​vostro codice e le interfacce se non lo avete mai fatto prima.

    Mentre i templates di progettazione sono certamente buoni da imparare, e alcuni sono estremamente potenti, non sono generalmente intrinsecamente orientati agli oggetti e come alcuni sostengono (e io tendo ad essere d'accordo) i templates di progettazione sono spesso solo delle debolezze esposte nella lingua. I templates di progettazione di una lingua sono i principi fondanti di base di un'altra persona. Quindi, quando si inizia, non rimanere impigliati sul fatto che qualche relazione sia un buon candidato per un ponte o una facciata; questo non è specifico del pensiero orientato agli oggetti, questo è legato a ciò che i costrutti di un linguaggio specifico permettono.

    Penso che sia utile analizzare prima un codice orientato agli oggetti esistente, decente e comprovato (ad esempio il codice sorgente Qt) in modo da poter avere un'idea di "come è fatto". Dopodiché, imparare da un libro o creare il tuo framework sarà molto più efficace.

    In generale, aiuta davvero a vedere le cose nel loro context prima di leggerle e praticarle, poiché ti dà dei momentjs per dire a te stesso: "Oh, ecco perché l'hanno fatto!" Alless è così che funziona per me.

    La parte difficile di OO è che le cose dovrebbero essere messe insieme in un unico object. Come hai già accennato all'evoluzione del tuo codice sorgente, qui hai una semplice guida su come evolvere il tuo codice sorgente verso un design OO:

     "Put stuff together that changes together." 

    Quando due pezzi di codice hanno velocità di cambiamento simili, è un suggerimento che dovrebbero essere collocati nello stesso object. Quando le velocità di cambiamento sono diverse, prendi in considerazione la possibilità di posizionarle in oggetti diversi.

    Questo è anche noto come "Change Velocity".

    Se segui quella linea guida, il tuo codice si evolverà naturalmente verso un buon design OO. Perché?

    Frammenti di codice hanno spesso velocità di cambiamento simili se accedono a una rappresentazione comune. Ogni volta che la rappresentazione cambia, tutti i pezzi di codice che lo utilizzano devono cambiare contemporaneamente. Questo fa parte del motivo per cui utilizziamo gli oggetti come moduli per incapsulare la rappresentazione. Separare l'interface dall'implementazione ha senso anche sotto questa linea guida – l'implementazione cambia più spesso e quindi ha una maggiore velocità di cambiamento.

    Se una class ha una parte stabile e una parte instabile, questa è una differenza nella velocità di cambiamento che suggerisce di spostare la parte stabile in una class di base (possibilmente astratta).

    Allo stesso modo, se una class ha due parti che cambiano allo stesso modo spesso ma in momentjs diversi o in direzioni diverse (vale a dire, per ragioni diverse), allora ciò suggerisce nuovamente di rifare la class.

    A volte sostituisci "class" con "metodo". Ad esempio, se è probabile che una row di un metodo cambi più spesso del resto – forse è la linea che crea una nuova istanza di object e contiene il nome della sua class – considera di spostarla nella sua stessa routine. Quindi le sottoclassi possono facilmente influire sul loro cambiamento sovrascrivendolo.

    Mi sono imbattuto in questo concetto sul wiki C2 molti anni fa , ma raramente l'ho visto da allora. Lo trovo molto utile. Esprime alcune fondamentali motivazioni alla base del design orientato agli oggetti. Certo, è quindi incredibilmente ovvio.

    Questi sono cambiamenti del programma. C'è un altro senso di velocità di cambiamento: non si desidera che le variables di istanza cambino a velocità diversa, o piuttosto che sia un segno di potenziali problemi. Ad esempio, in un editor di grafica non è necessario conservare le cifre e le maniglie nella stessa collezione, poiché le cifre cambiano una volta al minuto o una volta all'ora e le maniglie cambiano una volta al secondo o una volta al minuto.

    In una prospettiva un po 'più ampia, vuoi che un sistema sia in grado di cambiare abbastanza velocemente per tenere il passo con i cambiamenti nel business.

    PS: l'altro principio che dovresti seguire è "Law of Demeter", cioè un object dovrebbe parlare solo ai suoi amici. Gli amici sono: te stesso, variables di istanza, parametri, gente del posto e membri di raccolte amichevoli, ma non globali e variables statiche.

    Potresti considerare l'utilizzo dell'approccio alla carta CRC (Classe / Responsabilità / Collaborazione) alla progettazione OO. Questo non è niente di spaventoso – è solo un modo per risolvere ciò che dovrebbero essere i tuoi oggetti, e quale object dovrebbe essere responsabile di quali attività scrivendo cose su un mazzo di tabs per aiutare a chiarire i tuoi pensieri.

    È stato originariamente concepito come uno strumento didattico pensato da OO e potrebbe funzionare per te. Il documento originale è disponibile all'indirizzo: http://c2.com/doc/oopsla89/paper.html

    Un poster sopra suggeriva la programmazione in Smalltalk per costringerti alle abitudini OO, e in un certo senso questo è un buon suggerimento – Smalltalk certamente mi ha fatto molto bene, ma

    a) potresti non avere il tempo libero per imparare una nuova lingua. Se lo fai, bene.

    b) Ero solito seguire un corso universitario in programmazione OO, usando Smalltalk, e gli studenti hanno fatto un ottimo lavoro nel dimostrare quella vecchia battuta su come "Puoi scrivere FORTRAN in qualsiasi lingua".

    Infine: quando stavo imparando su OO (dai libri) ho avuto l'impressione di aver sottoclassato molto, creando complicate gerarchie di classi. Quando ho iniziato a lavorare con i programmatori OO mi sono reso conto che non accadeva tutte le volte che pensavo. Penso che tutti facciano questo errore quando stanno imparando.

    L'unico modo per scrivere codice migliore è scrivere più codice. Prendi un progetto che hai implementato proceduralmente e convertilo in OOP (supponendo che tu stia lavorando in una lingua che support entrambi). Probabilmente finirai con una soluzione fragile e strettamente accoppiata la prima volta, ma va bene. Prendi la ctriggers implementazione OOP e inizia a rifarla in qualcosa di meglio. Alla fine, capirai cosa funziona e cosa no.

    Quando sei pronto per fare il passo successivo, prendi un libro di templates di design e impara parte della terminologia del design OOP. Questo non è strettamente necessario, ma ti darà una migliore comprensione di alcuni dei problemi e delle soluzioni più comuni.

    Penso che dovresti convincere te stesso, ricercando tutti gli aspetti negativi della programmazione procedurale, ad esempio (alcune parole d'ordine che seguono, attenzione): portta, stato … praticamente sarai in grado di estrarre molti termini semplicemente leggendo esempi di templates di progettazione (leggi: esempi comuni di utilizzo degli oggetti insieme).

    Sottolineando te stesso per imparare qualcosa in cui non credi non ti porterà da nessuna parte. Iniziare a essere davvero fondamentale per il tuo lavoro precedente e refactoring per evitare il codice copiato e l'utilizzo dell'ambito globale, e ti troverai a volere di più.

    Per me il momento ah-ha di OOP è stata la prima volta che ho guardato il codice e mi sono reso conto che potevo refactoring cose comuni in una class base. Conoscete chiaramente come orientare il codice e riutilizzarlo, ma è necessario pensare attorno alle classi e non alle procedure. Con l'authentication dell'utente è chiaro che avrai un nome utente e una password, ora entrano nella class base, ma se hai bisogno anche di tokenId, riutilizza la tua class base di accesso esistente e crea una nuova sottoclass da quella con il nuovo comportmento, tutto il codice esistente funziona senza modifiche.

    Guarda come funziona per te.

    Bene, i primi schemi di progettazione sono la cosa peggiore su cui impostare la programmazione.

    È solo un grande insieme di cose. Non ha nulla a che fare con OOP e la maggior parte di essi, come Singleton, vengono costantemente utilizzati per tutte le ragioni sbagliate (ad esempio l'initialization). Alcune di queste cose che devi usare per raccontarti di esse sono inutili, altre sono controproducenti e il resto sono solo casi particolari. Se si tenta di imparare qualcosa in questo modo, tutto inizierà ad assomigliare ad un bizzarro doodad che qualcuno ha inventato per un problema molto speciale o perché aveva bisogno di una genericità infinita (che raramente è vera). Non lasciare che le persone ti riducano a utilizzare milioni di iteratori e templates senza motivo e rendere le cose dieci volte più complicate.

    In realtà OOP è un argomento semplice che viene massicciamente complicato. Sfortunatamente in C ++ ha molti problemi, ma i methods virtuali veramente semplici sono ciò che conta. Le classi di base virtuali pure utilizzate in modo molto simile a un object di interface java sono le più utili ma anche semplici methods virtuali qui e là torneranno utili.

    È stato per lo più esagerato. Inoltre non si presta bene ad each problema. Se crei database e file gui, questo si presta bene. Se si creano strumenti di sistema, di solito non è così utile.

    Ho scoperto che una delle cose che ha davvero contribuito a consolidare i vantaggi di OOP per me è stata la scrittura di unit test con un framework di oggetti simulati (come EasyMock ). Una volta che inizi a svilupparti in questo modo, puoi vedere come le classi ti aiutano a isolare i moduli dietro le interfacce e anche a facilitare i test.

    Una cosa da tenere a mente è che quando le persone imparano per la prima volta l'OOP, spesso c'è un'enfasi eccessiva sull'ereditarietà. L'ereditarietà ha il suo posto, ma è uno strumento che può essere facilmente abusato. La composizione o l'implementazione semplice dell'interface sono spesso modi migliori di fare le cose. Non andare così lontano nel tentativo di riutilizzare il codice tramite l'ereditarietà per creare alberi ereditari che hanno poco senso dal punto di vista del polimorfismo. Il principio di sostituzione è ciò che rende potente l'implementazione di ereditarietà / interface, non il fatto che è ansible riutilizzare il codice per sottoclassi.

    Non farlo.

    In primo luogo, impara a scrivere. In secondo luogo, impara l'esperienza dell'utente e il design dell'interazione. In terzo luogo, apprendi l'analisi aziendale. In quarto luogo, apprendi la modellazione dei ruoli.

    Ora che sai quali oggetti sono, verrai a vedere che gli oggetti non si trovano nel codice. Si trovano in fase di runtime; nello spazio tra la macchina e la mente dell'utente. Questo è ciò che significa veramente l'orientamento agli oggetti. Sfortunatamente il recente mondo accademico lo ha trasformato in un concetto ingegneristico. Niente potrebbe essere più lontano dal marchio. E prova come potrebbero emulare, il risultato finale è una schifezza. Perché? Perché il paradigma "OOP" come lo sa oggi l'industria si basa su un'idea fondamentalmente errata: analisi decomposizionale dell'identity framework;. Come è questo imperfetto? Perché l'identity framework; in sé e per sé non ha senso. È vuoto In senso matematico, in senso filosofico. Questo non è il modo in cui un essere umano percepisce e interagisce con il mondo.

    Canon: Alan Kay, Trygve Reenskaug, James (Jim) Coplien

    Come vorrei essere nella tua posizione. 🙂

    Un grande passo sarebbe iniziare con un framework OOP, è comunque ansible scrivere codice procedurale nel framework, ma nel tempo è ansible perfezionare le abitudini di codifica e avviare la conversione delle funzionalità in oggetti.

    Anche la lettura di templates e modellazione dei dati ti darà più idee su come codificare la tua logica in uno stile OOP.

    Ho scoperto che un modo molto intenso per imparare a formare l'astrazione nella programmazione è build una libreria OOP con una funzionalità definita, e quindi implementare due progetti con requisiti simili ma ancora diversi che si stanno costruendo su quella libreria, allo stesso tempo.

    Questo richiede molto tempo ed è necessario aver prima imparato le basi dell'OOP (S.Lott ha alcuni ottimi collegamenti nell'altra risposta). Costante refactoring e tanto "Doh!" i momentjs sono la regola; ma ho trovato questo un ottimo modo per imparare la programmazione modulare perché tutto ciò che ho fatto è stato immediatamente evidente nell'implementazione di uno dei progetti.

    Semplicemente pratica. Se hai letto tutto su OOP e sai qualcosa su OOP e conosci i principi OOP implementati nella tua lingua PHP … quindi esercitati, esercitati e pratica ancora un po '.

    Ora, non andare a vedere OOP come il martello e tutto il resto come un chiodo, ma cerca di incorporare alless una class in un progetto. Quindi vedi se puoi riutilizzarlo in un altro progetto, ecc.

    Impara una nuova lingua, una che ti aiuta a muoverti dolcemente verso OOP. Java è bello, ma un po 'gonfio, però. Ma la sua libreria di sistema è principalmente OO, quindi sei costretto a usare gli oggetti. Passare a un'altra lingua aiuta anche a non riutilizzare il vecchio codice 🙂

    Penso che sia importnte imparare la teoria prima. Quindi leggere un libro sarebbe un buon inizio.

    1. Credo che i meccanismi di OOP sembrino completamente arbitrari e non abbiano senso fino a quando non leggerai un libro sugli schemi di progettazione e capirai il "perché" di esso. Raccommand i primi disegni del capo. Pensavo che l'OOP fosse ridicolo e completamente inutile fino a quando non ho raccolto questo libro e ho visto a cosa serviva.

    2. OO ha molto più senso quando si capiscono i puntatori di function e in che modo si riferisce alle chiamate di function indirette e al binding tardivo. Gioca con i puntatori di function in C, C ++ o D per un po 'di tempo e fatti un'idea di cosa sono e come funzionano. La function di polimorfismo / function virtuale di OO è solo un altro strato di astrazione al di sopra di questo.

    3. Procedural è lo strumento giusto per alcuni lavori. Non comportrti come se fosse sbagliato. IMHO tutti e tre i principali paradigmi (procedurali, OO, funzionali) sono preziosi anche a un livello a grana fine, all'interno di un singolo module . Io tendo a preferire:

    Procedural è buono quando il mio problema è semplice (o ho già preso in considerazione abbastanza con funzionale e OO che ora ho un sottoproblema che considero semplice) e voglio la soluzione più semplice senza un sacco di astrazione di intralcio.

    Orientato agli oggetti è buono quando il mio problema è più complesso e ha un sacco di stato che ha senso nel context del dominio del problema. In questi casi l'esistenza dello stato non è un dettaglio di implementazione, ma la rappresentazione esatta è quella che preferisco astrarre.

    Il funzionale è buono quando il mio problema è complesso ma non ha uno stato che abbia senso a livello del dominio del problema. Dal punto di vista del dominio del problema, l'esistenza dello stato è un dettaglio di implementazione.