OOP vs programmazione procedurale - pagina 23

 
Maxim Kuznetsov:

Sembra che vi siate persi le chiacchiere :-) i moderatori hanno messo un freno ai topic flaming... ma qui si tratta di OOP vs.

A proposito, il 99% di @Peter Konow usa OOP, ma lui non ne è consapevole :-) OOP non è necessariamente "class & template".

E viceversa... la presenza di oggetti e classi in un programma non è indicativa di OOP

Questo è un pensiero molto interessante. Forse è così, e io non lo sospetto. ))


Ma come si fa a saperlo?

 
Реter Konow:

Questo è un pensiero molto interessante. Forse lo è, e non sospetto che lo sia. ))


E come fai a saperlo?

Per esempio, l'OO può essere implementato attraverso il dispatch dei messaggi (e con alcuni "plus" che non sono nella classe/template MQL),

Non ho guardato il tuo codice e probabilmente non sarò in grado di leggerlo, ma dato che hai una libreria GUI, sono sicuro che ha la sua (almeno una) coda e attraverso l'elaborazione di eventi/invii/stati è tutto avvolto. E questa stessa "torsione" alla fine è solo ereditarietà/polimorfismo.

 
Dmitry Fedoseev:

A proposito del riccio:

"Il riccio sta nella radura, in posa, flettendo i suoi bicipiti: - Sono forte, sono coraggioso, sono agile, sono forte, sono coraggioso, sono agile...

Un orso passa - gli dà un calcio una volta, il riccio vola dietro l'albero, si alza e si scuote:

- Sono forte, sono coraggioso, sono agile... ...ma sono leggero...


Come diceva il mio amico d'infanzia, il riccio è un uccello orgoglioso, se non gli dai un calcio, non vola ))
 
Alexey Volchanskiy:

Georges, ho fatto una piccola passeggiata con una ragazza oggi, abbiamo chiacchierato un po', ci siamo ricordati un po' degli uomini timidi. Onestamente, non mi prendo in giro, ognuno ha personalità diverse e un'educazione diversa.

Oh... E Lekha è per le ragazze... E giustamente. Molto più interessante del GOP.

Beh, il mio problema non è la timidezza. E' la "lingua ben tenuta" l'unica cosa di cui posso vantarmi. Il mio problema è il vaginocentrismo con l'assenza di pene. Do troppo valore alla privacy e al sesso. Hai scritto sopra: "...ho visto quanto duramente possono lavorare i ragazzi quando le belle donne incombono". Beh, io sono uno di quelli. Solo che le ragazze hanno bisogno di te finché sei giovane, forte e ricco. E se una ragazza ha la possibilità di fotterti, è destinata a farlo prima o poi. Anche uno giovane, forte e ricco. Io sono un vecchio invalido senza soldi e senza casa. Quindi le mie possibilità sono nulle... Non sono nemmeno sorpreso che mia moglie se ne sia andata. Solo che a te non sembra importare che tu sia divorziato. Io, d'altra parte, trovo estremamente frustrante di non aver potuto creare le condizioni per cui mia moglie non potesse andarsene.

 

E riguardo all'OOP...

Se avessi la stessa memoria di Retag Konow, probabilmente sarei d'accordo che l'OOP non è necessaria, che senso ha costruire tutte queste interfacce, classi, oggetti, sistema di ereditarietà e funzioni virtuali...

Alexey ha detto correttamente - il processore non sa nulla di nessun oggetto... Non sa nemmeno nulla delle funzioni. Il che dimostra che qualsiasi compito può essere risolto non solo senza OOP ma anche senza funzioni, semplicemente ricordando gli indirizzi di ritorno e passando il controllo tramite il registro IP (o qualsiasi cosa le CPU moderne usano oggi).

Non ho capito la posizione di Retug Konow finché non mi ha mostrato il suo codice. Ora tutto è chiaro e posso anche essere d'accordo con lui, se riesco a tenere tutto in memoria e i lunghi se non mi danno fastidio, ho il sospetto che sia più ragionevole scriverlo come fa lui. Inoltre, in questo caso OOP diventa davvero una "quinta ruota del carro".

Ma, personalmente, il mio problema è che la maggior parte delle sottigliezze del lavoro - mi sfugge. Per esempio, dimenticherò sempre di cosa è responsabile ogni indice nell'array multidimensionale G_CORE; in ogni condizione in un dato frammento - ogni volta penserò seriamente - cosa definisce. L'analisi delle condizioni lunghe sarà anche tesa per me.

E a volte io stesso scrivo questo codice che è difficile da capire. Ecco un frammento del MIO codice"errato" in cui affondo allo stesso modo (l'ho citato sopra):

virtual bool IsTPCInUnloss() const { if(GetTPCStopLoss() <= 0 || GetTPCStopLoss() == EMPTY_VALUE) return(false); if(GetTPCType() == POSITION_TYPE_BUY) { if(GetTPCStopLoss() >= GetTPCOpenPrice()) return(true); } else { if(GetTPCStopLoss() <= GetTPCOpenPrice())return(true); }; return (false); };

Questa è la funzione di interfaccia del componente di trading CTradePosComponentI, che determina se questo componente è in pareggio.

"La "scorrettezza" di questo codice è che la leggibilità è sacrificata qui a spese della compattezza e della leggibilità. Poiché la funzione è inclusa nell'interfaccia - volevo che l'intera interfaccia fosse visibile su uno schermo, se possibile. Solo per non dovermi ricordare quali caratteristiche fornisce, in modo che tutte quelle caratteristiche possano essere viste in una volta sola. Se ricordassi tutto - non ci sarebbe bisogno di "allungare" la funzione in una stringa. Quindi la funzione si è allungata su una dozzina di linee - bene... Tuttavia, era importante per me che tutte le funzioni si adattassero all'interfaccia una accanto all'altra, e che fossero tutte visibili. Volevo che uno sguardo all'interfaccia mi desse immediatamente un'idea dell'insieme di funzioni che fornisce. Ecco perché - ho dovuto scrivere le funzioni in una lunga linea. Tuttavia, è totalmente irrealistico capirlo.

Inizialmente, quando ho scritto il codice - ho scritto questa funzione in modo abbastanza diverso all'inizio. In modo chiaro e con commenti. Per poterlo capire.

Come questo:

virtual bool IsTPCInUnloss() const 
{ 
    // Отсеем вариант, когда СЛ отсутствует
    if(GetTPCStopLoss() <= 0 || GetTPCStopLoss() == EMPTY_VALUE)
         return(false);

    //  Проверим тип торговой компоненты
    if(GetTPCType() == POSITION_TYPE_BUY)
        { 
        // Торговая компонента - лонг
        if(GetTPCStopLoss() >= GetTPCOpenPrice())
            return(true);
        }
    else
        { 
        // Торговая компонента - шорт
        if(GetTPCStopLoss() <= GetTPCOpenPrice())
             return(true); 
        }; 

    return (false); 
};

E solo dopo che tutto questo è stato testato e debuggato - il codice è stato ripulito dai commenti e "messo in riga".

Ma questa è un'eccezione. Lo faccio molto raramente, in casi speciali quando la "visibilità" è importante. In tutti gli altri casi - scrivo codice sia "largo" che con indentazione, e con commenti in qualsiasi posto, dove potrebbe esserci il minimo intoppo con una domanda "cosa c'è qui".

Altrimenti, dimentico molto rapidamente dove, cosa e a cosa serve

 
Maxim Kuznetsov:

Per esempio, l'OO è abbastanza fattibile attraverso il message dispatch (e con alcuni "plus" che non sono nella classe/template MQL),

Non ho guardato il tuo codice e non posso leggerlo, ma dato che hai una libreria GUI, sono sicuro che ha la sua (almeno una) coda e attraverso l'elaborazione di eventi/sentenze/stati ci sono molte cose incasinate. E questa stessa "torsione" alla fine è solo ereditarietà/polimorfismo.

Bene, ora che ho detto "A", vorrei dire anche "B"). Descriverò la mia tecnologia in modo più specifico.

Combinando le funzionalità che lavorano su un particolare tipo di compiti in grandi blocchi, riduco il numero di collegamenti che devono essere costruiti tra le funzioni. Questo ha i suoi pro e i suoi contro.

Prima i professionisti:

In OOP, un meccanismo scomposto in un gran numero di funzioni, richiede la creazione di molti oggetti per collegare le classi e le strutture. Allo stesso tempo, ogni prototipo di funzione è circondato da un gran numero di parametri formali, attraverso i quali la funzione comunica con il codice circostante. La struttura interna del codice diventa più complessa proprio a causa dell'aumento dei collegamenti tra le parti del meccanismo durante lo sviluppo di questo meccanismo.

Nella mia tecnologia, la comunicazione tra le funzioni e i blocchi è semplificata interamente attraverso l'uso di variabili globali, che sono stampate in tutto. Le funzioni non hanno bisogno di passare parametri perché li vedono immediatamente a livello globale.

Ivalori delle variabili globali sono impostati dal blocco Object Focus, che "segue" il cursore. Utilizza le coordinate correnti del cursore per determinare su quale oggetto si trova il mouse e accede al kernel (G_CORE) che memorizza tutte le proprietà di tutti gli elementi, oggetti e finestre. Dal kernel, il blocco prende i valori attuali di tutte le proprietà principali dell'oggetto sotto il cursore e li mette nelle variabili globali. Se il cursore si sposta sugli oggetti, le variabili globali sono ridefinite in questo blocco e corrispondono sempre all'oggetto che è a fuoco.

Successivamente, la funzione OnChartEvent() cattura gli eventi del grafico che dovrebbero cambiare lo stato dell'elemento sotto il cursore. Su questi eventi, il blocco di controllo dello stato (che è integrato in OnChartEvent() stesso) vede immediatamente quale finestra, elemento e oggetto sono a fuoco e quali sono le loro proprietà. Non avete bisogno di passare nulla a questo blocco, perché tutto ciò di cui avete bisogno è già nel focus, nelle variabili globali. Il suo compito è cambiare i valori delle proprietà dell'oggetto nel kernel G_CORE e ridisegnare l'elemento. Cambia i valori e chiama il blocco Draw.

Solo tre parametri devono essere passati al blocco di disegno - finestra, tela ed elemento. Ridisegna l'elemento, dandogli un aspetto appropriato al suo stato attuale. Tutte le funzioni ausiliarie del blocco di pittura, utilizzano anche le variabili globali a fuoco. Per esempio, la funzione precedente "Color part()" usa "WINDOW", "OBJECT", "CATEGORY_OBJECT" ecc. Questi sono tutti molto utili.


Ora per i contro:

Indubbiamente, i grandi blocchi e gli oggetti focus semplificano la relazione tra le parti del codice, ma è a causa del fatto che i blocchi sono grandi, creando difficoltà quando si lavora con loro. La lingua russa e la totale semplificazione della sintassi mi aiutano qui, dato che non uso OOP.

Con il tempo, i blocchi arrivano al punto in cui non hanno più bisogno di essere cambiati e smettono di crescere. A poco a poco la loro struttura è completamente memorizzata e il lavoro con loro è semplificato al massimo.

Naturalmente, la rettifica dei blocchi in sé, è una cosa piuttosto lunga e dolorosa, ma questo è ciò che riguarda il debugging di qualsiasi meccanismo.

 
George Merts:

E riguardo all'OOP...

Se avessi la stessa memoria di Retag Konow, forse sarei d'accordo che l'OOP non è necessaria, che senso ha costruire tutte queste interfacce, classi, oggetti, sistema di ereditarietà e funzioni virtuali...

Alexey ha detto correttamente - il processore non sa nulla di nessun oggetto... Non sa nemmeno nulla delle funzioni. Il che dimostra che qualsiasi compito può essere risolto non solo senza OOP ma anche senza funzioni, semplicemente ricordando gli indirizzi di ritorno e passando il controllo tramite il registro IP (o qualsiasi cosa le CPU moderne usano oggi).

Non ho capito la posizione di Retug Konow finché non mi ha mostrato il suo codice. Ora tutto è chiaro e posso anche essere d'accordo con lui, se riesco a tenere tutto in memoria e i "se" lunghi non mi danno fastidio, ho il sospetto che sia più ragionevole scrivere come fa lui. Inoltre, in questo caso OOP diventa davvero una "quinta ruota del carro".

Ma, personalmente, il mio problema è che la maggior parte delle sottigliezze del lavoro - mi sfugge. Per esempio, dimenticherò sempre di cosa è responsabile ogni indice nell'array multidimensionale G_CORE; in ogni condizione in un dato frammento - ogni volta penserò seriamente - cosa definisce. L'analisi delle condizioni lunghe sarà anche tesa per me.

E a volte io stesso scrivo questo codice che è difficile da capire. Ecco un frammento del MIO codice"errato" in cui affondo allo stesso modo (l'ho citato sopra):

Questa è la funzione di interfaccia del componente di trading CTradePosComponentI, che determina se questo componente è in pareggio.

"La "scorrettezza" di questo codice è che la leggibilità è sacrificata qui a spese della compattezza e della leggibilità. Poiché la funzione è inclusa nell'interfaccia - volevo che l'intera interfaccia fosse visibile su uno schermo, se possibile. Solo per non dovermi ricordare quali caratteristiche fornisce, in modo che tutte quelle caratteristiche possano essere viste in una volta sola. Se ricordassi tutto - non ci sarebbe bisogno di "allungare" la funzione in una stringa. Quindi la funzione si è allungata su una dozzina di linee - bene... Tuttavia, era importante per me che tutte le funzioni si adattassero all'interfaccia una accanto all'altra, e che fossero tutte visibili. Volevo che uno sguardo all'interfaccia mi desse immediatamente un'idea dell'insieme di funzioni che fornisce. Ecco perché - ho dovuto scrivere le funzioni in una lunga linea. Tuttavia, è totalmente irrealistico capirlo.

Inizialmente, quando ho scritto il codice - ho scritto questa funzione in modo abbastanza diverso all'inizio. In modo chiaro e con commenti. Per poterlo capire.

Come questo:

E solo dopo che tutto questo è stato testato e debuggato - il codice è stato ripulito dai commenti e "tirato in linea".

Ma questa è un'eccezione. Faccio questo modo molto raramente - in casi particolari quando la "visibilità" è importante. In tutti gli altri casi scrivo codice sia "largo" che indentato, e con commenti in qualsiasi posto dove potrebbe esserci il minimo intoppo di una domanda "cosa c'è qui".

Altrimenti, dimentico molto rapidamente dove, cosa e a cosa serve

I nostri compiti sono molto diversi, quindi è difficile per me dire qualcosa sulle vostre soluzioni. Non sono sicuro che sia solo la mia memoria, ci deve essere qualcos'altro. Dare un senso al proprio codice migliora senza dubbio la sua memorabilità. Non sto dicendo che il tuo codice sia meno significativo. Non so proprio come affronterei i vostri problemi. Forse il tuo approccio è quello giusto. Non sto giudicando. Personalmente trovo questo stile di codice molto difficile da comprendere.

Credo che sia una questione di abitudine).

 
Реter Konow:

I nostri compiti sono molto diversi, quindi è difficile per me dire qualcosa sulle vostre soluzioni. Non sono sicuro che sia solo la mia memoria, ci deve essere qualcos'altro. Dare un senso al proprio codice rende senza dubbio più facile da ricordare. Non sto dicendo che il tuo codice sia meno significativo. Non so proprio come affronterei i vostri problemi. Forse il tuo approccio è quello giusto. Non sto giudicando. Personalmente trovo questo stile di codice molto difficile da capire.

Probabilmente è una questione di abitudine).


È una conversazione completamente insensata: non c'è un criterio di categorizzazione del codice come "buono" o "cattivo". Ecco perché non è chiaro l'OOP.

Per me tale criterio è la FATTIBILITÀ del codice, che si manifesta nel fatto che l'autore o una terza parte può leggere il codice dopo un periodo di tempo piuttosto lungo e usarlo per modificarlo, per trovare bugs.....


Qui sopra Fedoseyev ha sostituito l'interruttore OOP. Questo particolare esempio, forse sfortunato, per me è una prova della cattiveria dell'OOP: un codice chiaro con un interruttore di 100 posizioni è sostituito da una sola linea. Per capire questa linea bisogna andare da qualche parte. Non è ammissibile per me.

Il secondo esempio qui sopradi George Merts

Quando il codice chiaro è stato sostituito da un codice NON chiaro dopo il debug. Secondo il mio criterio il codice di qualità (facile da leggere) è stato sostituito dal codice che non è accettabile per me.


Quindi ho una domanda a tutti i sostenitori di OOP: il programma diventa più visibile quando si applica OOP e l'esempio dato da Fedoseev sullo switch è un fallimento o al contrario, l'esempio di Fedoseev caratterizza molto accuratamente OOP e OOP porta quasi sempre a una perdita di visibilità?

 
СанСаныч Фоменко:

1. Una conversazione completamente inutile: non esiste un criterio per classificare il codice come "buono" o "cattivo". Ecco perché non è chiaro l'OOP.

Per me, tale criterio è la FATTIBILITÀ del codice, che si manifesta nel fatto che l'autore o una terza parte può leggere il codice e usarlo per modificarlo, trovare bug dopo un periodo di tempo abbastanza lungo.....


2. Qui sopra Fedoseyev ha sostituito l'interruttore OOP. Questo particolare esempio, forse sfortunato, per me è una prova di cattiveria dell'OOP: il codice chiaro con un interruttore a 100 posizioni è sostituito da una sola linea. Per capire questa linea bisogna andare da qualche parte. Non è ammissibile per me.

Il secondo esempio qui sopradi George Merts

Quando il codice chiaro è stato sostituito da un codice NON chiaro dopo il debug. Secondo il mio criterio il codice di qualità (facile da leggere) è stato sostituito da inaccettabile per me.


3. Quindi ho una domanda per tutti i sostenitori di OOP: il programma diventa più visibile quando si applica OOP e l'esempio dato da Fedoseyev sullo switch è un fallimento, o al contrario, l'esempio di Fedoseyev è una descrizione molto accurata di OOP e OOP porta quasi sempre a una perdita di visibilità?


1. C'è un criterio. Il criterio principale è la velocità.

La chiarezza del codice è il criterio sbagliato. Il codice non è scritto per essere guardato, ma per funzionare.

2. Capisco, si scopre che alcuni di noi non sono abbastanza maturi per strutturare il nostro codice con le funzioni. Quindi sei nell'argomento sbagliato, dovresti affrontare l'argomento "codice di una pagina vs. codice strutturato a funzioni".

Inoltre, il campione non riguardava la strutturazione e la chiarezza/non-ovvietà, ma l'eliminazione dei frammenti di codice di zavorra.

3... perché non... Iniziare a fare grafica ingegneristica? O la geometria descrittiva. Lì è tutto molto visivo.

 
Dmitry Fedoseev:

La visibilità del codice è il criterio sbagliato. Il codice non è scritto per essere guardato, ma per funzionare.

Beh, non sono d'accordo.

La visibilità del codice è una cosa molto importante perché un codice chiaro è molto più facile da mantenere e modificare.

Proprio così - ho scritto una funzione nuda e poi l'ho effettivamente "offuscata", resa non visibile e incomprensibile. Questa è stata una decisione forzata. In questo caso, era più importante per me rendere l'intera classe trasparente. Ho sacrificato la chiarezza di una funzione abbastanza banale. Naturalmente, avremmo potuto mettere il corpo di questa funzione nel file .mq5, ma credo che le interfacce non dovrebbero essere divise in due file e dovrebbero essere completamente descritte nel file header .mqh.

Anche la velocità è qualcosa da tenere a mente, ma non credo che dovremmo sforzarci per la "velocità a tutti i costi". Ci deve essere una ragionevole sufficienza.