Traduzione in Italiano di: Antonio Campagna - Maggio 2000

OOP.HOW

(c) 1995 A.A.Katz, All Rights Reserved.

 By A. A. Katz


Introduzione

Muoversi nella programmazione OO, é spesso difficile anche per programmatori esperti. Prima di OOP, imparare un nuovo linguaggio, consisteva soltanto nell'impadronirsi della nuova sintassi. OOP, richiede molto più. Un maggiore sforzo nel modo di immaginare i programmi, ed il relativo codice. Devo ammettere, che il processo di apprendimento é difficile. Ma i benefici sono talmente enormi, da compensare il tempo impiegato, ad imparare questa nuova metodologia di programmazione.

Visual dBase 5.x, ha una delle più semplici, ed allo stesso tempo più eleganti implementazioni, di OOP. E' la piattaforma perfetta, per il  primo progetto Object-Oriented.


Che cosa è OOP?

OOP è una metodologia di programmazione, che fa uso di "oggetti".Gli oggetti si possono definire come delle entità, che hanno "in se" determinati attributi (proprietà) e determinati comportamenti (metodi).

Quali differenze con le architetture di programmazione precedenti?

Se hai già programmato, probabilmente hai usato metodi procedurali. I tuoi programmi cominciavano dal punto "A", andavano al punto "B" e ritornavano al punto "A". L'interfaccia utente, era basata, su una struttura a menu gerarchico. L'utente utilizzava il programma, tramite menu innestati e tornava indietro, utilizzando il tasto <ESC> o qualche altro tasto, predefinito dal programma.

In OOP, gli oggetti, sono "lanciati", creati, attivati - ed il controllo e nelle mani dell'utente finale. Non esiste un modo "obbligato" per muoversi nel programma.

Ciascun oggetto, ha la sua propria "vita" indipendente da tutti gli altri oggetti.


Perché OOP?

Per Il Programmatore: Il beneficio principale (fra i tanti), che OOP offre al programmatore, è la "riutilizzabilità". Se ben progettati, gli oggetti possono essere riutilizzati, in qualsiasi programma senza adattamenti. Gli oggetti non richiedono: dichiarazione di variabili, chiamate a procedure, ecc.

Teoricamente, potresti scrivere, interi programmi, con poco o addirittura nessun codice. Dovresti appena combinare gli oggetti, insieme a poche proprietà e via in esecuzione....

Per L'Utente: In genere, i programmi sviluppati con OOP, danno agli utenti diversi "poteri". Ciascun utente, può personalizzare il programma, per adattarlo al loro ambiente di lavoro, tramite la selezione degli oggetti, in funzione del loro compito e delle loro abitudini, e non, secondo uno schema rigido condizionato da un menu gerarchico.


Concetti OOP

La programmazione OO, è basata su una manciata di concetti chiave.Devi conoscerli bene, per creare classi di oggetti effettivamente riutilizzabili.

Incapsulazione

Non puoi influire sul controllo degli oggetti da parte del tuo utente. Non hai assolutamente idea, di quanti oggetti, di quale genere, il tuo utente visualizzerà sullo schermo in un dato momento. Il migliore modo per assicurare che tutto lavorerà insieme, malgrado le scelte dell'utente, è garantire che ogni oggetto lavorerà solo ed indipendentemente. Ciascun oggetto, deve contenere tutti i suoi dati e le sue procedure, ed essere completamente isolato da ogni altro oggetto.

Non permettere che un oggetto "ricopra" un altro. O che una procedura di un oggetto, vada in esecuzione con i dati di un altro oggetto!  N.B. Quando ci riferiamo ai dati di un oggetto, non stiamo parlando delle tabelle dati.

Gli oggetti possono, e spesso fanno, condividere le tabelle. I dati di un oggetto sono i valori memorizzati nelle proprietà dell'oggetto.

E' importante isolare questi dati.

Se hai sullo schermo due "finestre Client" , ciascuna finestra ha i suoi dati e le sue caratteristiche, protette l'una dall'altra.

Isolare queste proprietà e questi comportamenti dicesi  "Incapsulazione".

Ereditarietà.

Gli oggetti, hanno la capacità di ereditare attributi (proprietà) e comportamenti (metodi), da altri oggetti. Questo è un aspetto delicato, dal punto di vista della riutilizzabilità. Per riutilizzabilità si intende, la capacità di modificare un oggetto in una specifica applicazione, senza doverlo riscrivere.

Presumi, per esempio, di creare un oggetto AUTOMOBILE. Esso possiede alcune proprietà (come i pneumatici, il motore ecc) ed alcuni comportamenti (partenza,frena, fai il pieno ecc) che possono essere ereditabili.

Infatti, usando OOP, puoi creare un nuovo oggetto, chiamato ELICOTTERO derivato da  AUTOMOBILE. Il nuovo oggetto ELICOTTERO, possiede tutte le proprietà ed i comportamenti di AUTOMOBILE, con in più alcune proprietà (rotore) ed alcuni comportamenti (decolla) specifici, ovviamente ad un elicottero.

Si dice che ELICOTTERO ha ereditato le proprietà (pneumatici, motore) ed i comportamenti (parti,arresta) da AUTOMOBILE.

Tramite l'eredità, la produttività viene enormemente migliorata. Usando OOP, non dovresti avere la necessità di "reinventare la ruota".

Polimorfismo.

Gli oggetti, possono modificare i comportamenti e le proprietà che hanno ereditato.

L'oggetto "figlio", può ridefinire i comportamenti "parti" e "arresta" di AUTOMOBILE, più opportunamente per ELICOTTERO, cambiando questi comportamenti in "decolla" e "atterra."

Il Polimorfismo (che letteralmente significa, "forme multiple") migliora la riutilizzabilità degli oggetti. Non devi scartare a priori, che l'oggetto AUTOMOBILE possa essere "genitore" (parent)  per l'oggetto ELICOTTERO, solo perché le proprietà "parti" e "arresta" (di AUTOMOBILE) non descrivono accuratamente il comportamento di ELICOTTERO.


Un Glossario OOP

E' perfettamente naturale, quando si studiano nuovi concetti, cercare di trovare analogie in quello che si é studiato in passato. In questo caso non farlo!

Ti verrà più facile comprendere la programmazione OO, se hai familiarità con i relativi termini. Perciò, può aiutarti, prima di proseguire,un vocabolario di programmazione Object-Oriented:

Class

Una Classe è la definizione di un oggetto.

CLASS Automobile &&classe

This.Tires = 'Radial'

This.Engine = 'Six Cylinder'

This.Trunk = 'Hatchback'

This.Start = CLASS::Turn key

This.Stop = CLASS::Press Brake

ENDCLASS

Suggerimento:

Molti principianti confondono una CLASSE con un programma o una procedura.Una CLASSE non è codice eseguibile. E' solo una "copia" un "modello" di un determinato oggetto.

 


SubClass

Una classe derivata "figlia" , ereditata da un'altra classe.

CLASS Helicopter of Automobile  && subclass

This.Rotors = 6

This.Start = CLASS::Take_Off

This.Stop = CLASS::Land

ENDCLASS


SuperClass

La classe "genitore" di una sottoclasse. Ad esempio AUTOMOBILE è la "SuperClass" di ELICOTTERO.


Proprietà 

Le proprietà sono simili alle variabili, infatti, sono usate per memorizzare informazioni. Una proprietà Cognome agisce nello stesso modo di una variabile Cognome - cioè  provvede a memorizzare spazio per i vari possibili Cognomi. Comunque, diversamente dalle variabili, le proprietà non "appartengono" ai programmi o alle procedure, ma, appartengono all'oggetto.

Le proprietà definiscono le caratteristiche (gli attributi) di un oggetto.

CLASS Helicopter of Automobile

This.Rotors = 6 &&Proprietà

This.Tires = 'Pirelli'

This.Engine = 'Jet'

ENDCLASS

Il passaggio meraviglioso, dalla programmazione procedurale alla programmazione OO, è il modo in cui le proprietà si riflettono sull'oggetto.Se volevi cambiare il valore di un campo, dovevi immettere il nuovo valore e poi rivisualizzarlo:

cMiaVar = "Ciao"

@ 2,1 say cMiaVar 

Nella programmazione OO, la modifica è incapsulata, é un comportamento dell'oggetto:

OO: This.Value = 'Ciao'

Gli effetti di una modifica di una proprietà, si riflettono automaticamente sullo schermo, non hai bisogno dell' istruzione 

@2,1 say cMiaVar, ciò fa risparmiare molto codice .


Metodo  

Un metodo, è il codice che esegue il "comportamento" di un oggetto. Tale "comportamento" viene implementato tramite le procedure e le funzioni. I metodi sono procedure e funzioni che appartengono ad un oggetto.

CLASS HELICOPTER OF AUTOMOBILE

This.Start = CLASS::TakeOff

PROCEDURE Take Off   &&Metodo

if CLASS::Checklist()

if CLASS::TurnEngineOn()

if CLASS::Taxi()

if CLASS::GetClearance()

CLASS::LiftOff()

endif

endif

endif

endif

ENDCLASS


Istanza 

L'attuale "oggetto" derivato da una Classe.

Define AlansCar of Automobile &&istanza

Define JanesHelicopter of HELICOPTER

OO supporta le istanze multiple simultaneamente della stessa classe.

Define AlansCar of Automobile &&Istanze multiple

Define JanesCar of Automobile

Define OurFamilyCar of Automobile

MyCar = New Automobile() &&Istanze multiple utilizzo New invece di Define

Le istanze sono gli oggetti che l'utente finale vede e usa. Le classi e le sottoclassi, sono gli strumenti di programmazione che usi per crearle.

Istanziare 

Creare una singola istanza di una classe in memoria.

In altre parole, si costruisce un oggetto dalla definizione di classe. Questo è simile alla "costruzione di una casa." La classe è il "modello" il "progetto".

Quando crei un'istanza, Visual dBase costruisce "la casa" dal "progetto" fornito nella definizione di Classe.

DEFINE AlansCar of Automobile &&istanza

oppure

AlansCar = New Automobile()


Oggetti Contenitori 

Alcuni oggetti hanno la capacità di contenere altri oggetti, ad esempio l''oggetto Scheda.

Una scheda può contenere pulsanti, oggetti browse,oggetti editor, etc.

Ovviamente, un pulsante (pushbutton), il quale non è un oggetto contenitore, non può contenere una scheda o un browse o un editor.


Classi standard 

Visual dBase, include circa 30 classi standard dalle quali puoi creare istanze o sottoclassi custom.

Schede, oggetti array e controlli schermo come pushbuttons, entryfields, browses e checkboxes sono tutte classi standard.


Classe base

La Classe Base è la "copia" dell'oggetto Scheda che è usata ogni volta che crei una nuova scheda usando "Impostazione Scheda".

Visual dBase, ha una nuova stupefacente capacità che ti lascia usare le proprie schede come Classe Base per nuove schede.

Questo è estremamente utile per standardizzare il "look" e l'uso di un'applicazione.

La tua Classe Base può includere pulsanti di una speedbar, titoli, barre di stato, rettangoli ed ogni altro controllo che desideri appaia su tutte le nuove schede.

Quando definisci la tua Classe Base, le schede che vengono generate sono sottoclassi della terza generazione:

1. Form &&Classe base Predefinita

2. Class AUTOMOBILE of Form() && La tua nuova classe base la quale è una sottoclasse di form

3. Class HELICOPTER of AUTOMOBILE && La tua nuova classe, derivata Automobile, che a sua volta era derivata da form

 


Classi Custom  

Visual dBase ti permette di creare classi custom da classi "scratch", da classi standard o da altre classi custom.

Class Automobile && da scratch

Class Automobile(f,n) of Form(f,n) && da Classi base 

Class Helicopter(f,n) of Automobile(f,n) && Da Classi custom 

Le classi che crei sono chiamate Classi Custom per distinguerle dalle Classi standard predefinite.


Costruttore  

Il Codice Costruttore è quella parte della classe "modello" per gli oggetti. Include tutte proprietà ed i loro valori. Non include i metodi della classe (procedure e funzioni). Nel caso di un oggetto contenitore, come la scheda, il codice costruttore include anche la definizione di tutti gli oggetti contenuti nella scheda.

Non puoi aggiungere nuove proprietà o metodi nel codice Costruttore di un oggetto usato con gli strumenti Two-Way come Impostazione Scheda e Impostazione Menu. Questa area è riservata per gli strumenti. Puoi, comunque,impostare valori o includere o rimuovere proprietà predefinite.

Per aggiungere nuove proprietà, devi costruirle dentro classi custom o aggiungerle dinamicamente durante un evento come ad esempio OnOpen.

 

CLASS Myform(f,n) of Form(f,n)

This.Top = 2

This.Left = 2

This.Width = 40

This.Height = 20

DEFINE PUSHBUTTON PUSHBUTTON1 OF THIS; 

PROPERTY;                      && Costruttore

Top 3,; 

Left 3,; 

Width 5,; 

Height 1.06,; 

ColorNormal "W+/N" 

PROCEDURE FORM_OnOpen    && Metodo

This.FormNumber = 2 

&& La procedura  FORM_OnOpen si definisce metodo quando è inclusa 

&& nella definizione dei metodi della classe. Qualche volta è anche chiamata "membro"

 &&  This.FormNumber  è una proprietà custom della scheda

ENDCLASS


Programmazione "guidata da eventi"

La chiave di volta dai linguaggi procedurali in ambiente DOS all' ambiente Windows e Visual dBase è la programmazione "guidata da eventi".Questo non è un concetto OOP. Nella programmazione "guidata da eventi" l'applicazione diviene reattiva, cioè al verificarsi di qualcosa (evento) essa reagisce ed esegue il comportamento (metodo) associato a quell'evento.

Un evento può essere un click del mouse (OnClick), la pressione di  un tasto. Può essere passare ad un altro programma o finestra (onGotFocus, OnLostFocus). Può essere un evento interno di Visual dBase, come la convalida di una immissione di dati (Valid) o permettere l'accesso ad un controllo (When).

Un programma "guidato da eventi" consiste di solo due elementi fondamentali:

Il tuo codice di interfaccia utente consiste di "opportunità" per gli eventi:Schede, pushbuttons, menu, oggetti browse,editors, entryfields, etc.

Il tuo codice "cosa-se" consiste di un "gestore evento".

Visual dBase, cattura un evento come un click del mouse, guarda se esiste un "gestore evento" per quel particolare evento ed oggetto. Se c'è, Visual dbase "attiva" l'evento - lancia cioè la procedura o la funzione collegata all'evento.

per costruire un gestore evento, devi semplicemente collegare il tuo codice (metodo) all'oggetto che attiva l'evento:

 

CLASS MyForm(f,n) of Form(f,n)

This.top = 2

This.left = 2

This.Height = 20

This.Width = 40

Define PUSHBUTTON1 of This;       &&oggetto

Property;

Top 4,;

Width 20,;

Text 'Press this button',;

OnClick CLASS::PUSHBUTTON1_OnClick        && Link al gestore evento

PROCEDURE PUSHBUTTON1_OnClick                 &&metodo gestore evento

This.ColorNormal = 'R/W'

This.Text = 'Button is Pressed'

ENDCLASS

Ciascun oggetto standard, ha i suoi propri eventi predefiniti. Per un elenco di eventi per ciascuna classe di oggetto, seleziona l'oggetto in impostazione scheda, premi il tasto destro del mouse e dal menu pop up seleziona "ispezione" quindi  seleziona la pagina eventi, la quale elenca gli eventi disponibili per l'oggetto selezionato.

Di seguito viene indicato un elenco molto parziale di eventi e quando sono attivati:

OnOpen (quando una scheda é aperta)

OnClick (quando si clicca il tasto sinistro del mouse)

OnGotFocus (Esegue una subroutine quando un oggetto viene focalizzato)

OnLostFocus (Esegue una subroutine quando il fuoco viene rimosso da un oggetto)

Valid (Specifica una condizione che deve esser vera (.T.) prima che l'utente possa spostare il fuoco da un oggetto.)

When (Specifica una condizione che deve essere vera (.T.) prima che l'utente possa focalizzare un oggetto)

OnClose (quando una scheda viene chiusa)

CanClose (Esegue una subroutine che determina se una scheda può essere chiusa, quando viene effettuato un tentativo di chiusura della scheda)

CanNavigate (Esegue una subroutine che determina se il puntatore ai record può spostarsi da un record a un altro)

OnChange (Esegue una subroutine quando l'utente modifica il valore visualizzato in un oggetto)

OnLeftDblClick (quando l'utente effettua un doppio click sul tasto sinistro del mouse)

OnSelChange (Esegue una subroutine quando l'evidenziazione viene spostata da una voce a un'altra in una casella di riepilogo o in un separatore)

 

Suggerimento: 

L'inclinazione iniziale dei programmatori procedurali è cercare di usare Visual dBase e Windows per emulare le loro precedenti strategie procedurali.

Una volta ancora, non farlo!

Non otterrai i benefici di OOP, windows e Visual dBase. 

I Calcoli sono fatti spesso dall'evento OnChange.I records sono aggiunti, salvati o abbandonati dall'evento evento OnClick di un pulsante o da un evento CanNavigate di un oggetto Browse. Nuovi oggetti sono lanciati da un evento OnClick  di un menu o di un  pulsante.

La convalida dei dati, è anche gestita differentemente nella programmazione guidata da eventi. Hai probabilmente usato convalidare ciascun campo prima di passare al prossimo.Nei programmi controllati dagli eventi non esiste una rigida sequenza di azioni. Il modello controllato da eventi fa la maggior parte dell'operazioni di convalida in un singolo evento OnClick di un pulsante "OK" o "Salva".

Guarda  tutti i dati degli oggetti, non a un campo alla volta per compiere la convalida dei dati:

 

PROCEDURE OKBUTTON_OnClick

if empty(Form.Entyfield1.Value)

MsgBox('Spiacente, Richiesto Numero Cliente!')

Form.Entryfield1.SetFocus()

elseif empty(Form.Entryfield2.value)

MsgBox('Spiacente, Richiesto Numero Cliente!')

Form.Entryfield2.SetFocus()

elseif etc....

else

Select MyTable

Form.SaveRecord()

endif


Il Riferimento Oggetto

Se hai necessità di avere istanze multiple di ELICOTTERO, dovrai poter distinguere tra MIOELICOTTERO e TUOELICOTTERO.

Le istanze nella vita reale sono identificate da nomi, numeri di serie ecc.

Una istanza di una classe, è distinguibile da un' altra tramite la propria variabile di riferimento all'istanza - un unico "nome" per ciascuna istanza di ciascuna classe.

Il "nome" di un oggetto è qualche volta anche chiamato Variabile di Riferimento Oggetto.

Come la maggior parte dei riferimenti indiretti, in programmazione (variabili, campi, etc.), la Variabile di riferimento all'istanza contiene l' indirizzo dell'oggetto, non l'oggetto stesso.

oMyHelo = New Helicopter()

Nella linea di codice precedente, Visual dBase crea un nuovo oggetto Helicopter e memorizza il suo indirizzo nella variabile oMyHelo.

Una volta che hai ottenuto da un oggetto, la sua Variabile di riferimento all' istanza(in altre parole il suo indirizzo), puoi "parlare" con l'oggetto direttamente - cambiare le sue proprietà, aggiungere proprietà nuove, attivare i suoi metodi:

oMyHelo = New Helicopter()        && Crea una nuova istanza

oMyHelo.TailNumber = 'A23456' && Definisce una nuova proprietà

oMyHelo.Entryfield1.Value = 1    && imposta un valore di default

oMyHelo.Open()                             && Apre la scheda

oMyHelo.Entryfield1.SetFocus() &&attiva il metodo SetFocus()

Come puoi osservare la variabile di riferimento all'istanza ti da un enorme controllo sull'oggetto.

Puoi inizializzare valori di default, prima dell'apertura, rendere visibili o invisibili alcuni oggetti, abilitare o disabilitare altri. Infatti puoi fare qualsiasi cosa dall'esterno o dall'interno dell'oggetto fino a quando hai la variabile di riferimento all'istanza.

La variabile di riferimento all'istanza é una variabile come ogni altra. Puoi passarla come un parametro memorizzarla in un altra variabile

cCurrHelo= oMyHelo

e rilasciarla.

Questo ovviamente ha un "costo". La variabile di riferimento all'istanza è anche visibile come qualsiasi altra variabile.

E, se la variabile di riferimento all'istanza va fuori "portata", hai perso tutte le possibilità di impostare e leggere le proprietà, o di attivare i metodi dall'esterno dell'oggetto.

Se l'istanza di riferimento è una variabile privata, scompare quando la procedura corrente termina, anche se l'oggetto è ancora attivo sullo schermo!

Un altra potenziale "buca", quando stai usando una variabile per memorizzare l'indirizzo di una istanza, è la sovra scrittura della stessa quando tenti di creare istanze multiple:

oMyHelo = New Helicopter() &&Prima Istanza

oMyHelo = New Helicopter() &&Seconda Istanza

La seconda istanza ricoprirà la prima, di conseguenza la prima resta orfana - e non può essere più indirizzata in nessun modo.

Impostazione Scheda, gestisce questo problema, aprendo automaticamente tutte le schede con una variabile LOCALE. Dopo tutto puoi avere un numero illimitato di copie di una variabile LOCALE:

LOCAL f

f = New Myform()

f.Open()

Questo fatto ha anche un aspetto "limitativo". Poiché "f" è LOCALE  è solamente visibile alla procedura nella quale è stata dichiarata, nessuno altro oggetto, procedura o funzione può indirizzare la scheda "f."

Soluzione: Cerca di memorizzare le tue Istanze di Riferimento (indirizzi dell'oggetto) in proprietà il più possibile. Ricorda che le proprietà sono visibili agli oggetti, non alle procedure.

 Procedure HeliLookupButton_OnClick

Set procedure to c:\HeliLook.Wfm Additive

Form.oLookup = New HeliLookForm() && Istanza di Riferimento memorizzata i una proprietà custom di una scheda

Form.oLookup.Open()

Se hai bisogno di aprire e gestire istanze multiple di una scheda, a richiesta dell'utente, puoi anche memorizzare le tue istanze di riferimento in un array. Oppure, puoi "attaccare" le istanze di riferimento direttamente all'oggetto applicazione di dBase (_app) per avere un campo di definizione "PUBLIC".

(Vedi nelle sezioni seguenti: Form, This., Class::, Super:: and _app)

Un caso comune nel quale le schede possono avere bisogno di "parlare" tra di loro, è ad esempio, una scheda "figlia" di controllo (lookup). Dove la scheda figlia deve impostare una proprietà nella scheda genitore quando un controllo (lookup) è completato con successo. Per fare questo, la "figlia" deve conoscere l'istanza di riferimento del genitore (o semplicemente l'indirizzo).

Il modo più facile per "passare" l' "indirizzo" del genitore è creare una proprietà custom nella scheda "figlia" prima di essere lanciata - e memorizzare in essa il riferimento del genitore:

Nella Scheda "Genitore"

Procedure CustomerLookUpButton_OnClick

Set Proc to C:\CustLook.Wfm

Form.oChild = New CustLookForm()

Form.oChild.ParentName = Form  && Memorizza  l'indirizzo della scheda genitore  

                                                           &&  in una proprietà custom della scheda figlia

Form.oChild.ReadModal()  && Apertura modale

Nella scheda "figlia"

Procedure OKButton_OnClick

Form.ParentName.Entryfield1.Value = Customer->CustNo

Form.Close()

La capacità di una scheda di parlare con un altra è chiamata "Comunicazione tra processi."

Form, This, Class::, Super::, _app

Tutte le architetture di programmazione, forniscono elementi tramite i quali, il programmatore può riferirsi durante la fase di progettazione dell'applicazione, riferimenti che non saranno conosciuti mentre il programma è in esecuzione.

Quando scrivi un programma, non hai idea di quali dati l'utente immetterà.

Così il tuo linguaggio ti da campi,variabili,array, macro-espansioni e codeblocks come un modo di riferirsi a dati "sconosciuti durante la fase di progettazione".

Anche gli oggetti sono "ignoti durante la fase di progettazione". Come programmatore, tu progetti le classi dalle quali gli oggetti saranno creati. Ma, è l'utente che determinerà quante istanze di quale oggetti saranno sullo schermo in fase di esecuzione.

Visual dBase, fornisce speciali elementi di linguaggio OOP che ti permetteranno di riferirti ad oggetti non ancora creati:

Form 

 "Form" è una variabile predefinita che si riferisce all'istanza di riferimento della scheda corrente.

Al programmatore, fornisce un conveniente riferimento all' oggetto contenitore durante la fase di progettazione, nonostante l'oggetto non sia stato istanziato.

Può essere usato all'interno di una scheda per fare riferimento a se stessa, ma può essere passato come proprietà o parametro ad altre schede, procedure e funzioni.

Do MyProc with Form

oppure

ReCalc(Form)

Si presume che istanzi la scheda con: oMyHelo = New Helicopter().

Quando usi "form" dall'interno della scheda, form é uguale a oMyHelo.

oMyHelo = New Helicopter()

Class Helicopter(f,n) of Automobile(f,n)

This.Width = 40

This.Height = 40

This.OnOpen = FORM_OnOpen

Procedure FORM_OnOpen

Form.Height = 60 &&Form=oMyHelo

Endclass

 

This 

"This", è un' altra generica variabile predefinita, che memorizza un riferimento oggetto. Diversamente da Form, la quale si applica solo all'oggetto contenitore, "This" può riferirsi a qualsiasi oggetto.

Se sei nell'area di definizione della scheda

This = Form

Se sei nella definizione di un controllo dentro una scheda:

This = Form

Se sei in un metodo (procedura o funzione fra una classe):

This= il Controllo che ha chiamato questo Metodo

Esempio:

Class MyForm of Form

This.Width = 24 && this si riferisce alla scheda (form)

This.OnOpen = Form_OnOpen

Define Text MyText of This; &&Si riferisce alla scheda 

Property;

Width This.Width,;            && Si riferisce alla scheda

OnOpen MyText_OnOpen

Procedure Form_OnOpen

This.Width = 40          && Si riferisce alla scheda  

Procedure MyText_OnOpen

This.Width = 10 && Si riferisce a  MyText

Class:: e Super::

Class:: e Super:: sono chiamati "Operatori di definizione del campo di azione". Questi operatori "dicono" a Visual dBase dove cercare un metodo. "Class:: MyProc" dice a Visual dBase di guardare SOLO nella classe corrente per il metodo "MyProc.", di non guardare dentro altre classi, o in UDF con lo stesso nome e di non cercare in una procedura esterna o nella SuperClass (se c'è una).

"Super:: MyProc" dice a Visual dBase di guardare solo nella SuperClasse della classe corrente, non nella classe corrente o qualche altra UDF o procedura. Questi due operatori, Super:: e Class:: sono fondamentali  dal punto di vista del polimorfismo (la capacità di avere la priorità di un metodo di una classe con un altro).

Tramite l'uso di questi Operatori di definizione del campo di azione, puoi esplicitamente "dire" a Visual dBase quale metodo chiamare:

Class HELICOPTER of AUTOMBILE

...

...

Define Pushbutton StartButton of This;

Property;

 

OnClick CLASS::Start && Esegue il metodo definito nella classe elicottero (corrente)

&&"start" method.

OnClick SUPER::Start && Esegue il metodo definito nella classe automobile (livello superiore)

&&"start" method.

Endclass

Suggerimento: "Super::" si riferisce genericamente ai metodi di una classe di  "livello superiore".Se ELICOTTERO nell'esempio su visto è su una scheda:

 Define Automobile HELICOPTER of This;

Property;

OnClick SUPER::OnClick

"Super::" si riferisce alla scheda. O al meno controlla se la scheda possiede un evento OnClick. Se cosi non fosse, Visual dBase cercherà nella gerarchia di classi definita fino a quando troverà un metodo con il giusto nome.
Forse un chiarimento più accurato per Super:: potrebbe essere "il prossimo livello che Visual dBase trova".
Questo può essere molto utile quando hai una classe custom basata a sua volta su un 'altra classe custom e così via.
 

_app  

"_app" è il nome dell'oggetto applicazione predefinito di Visual dBase. Questo oggetto è il "genitore" del tuo programma. E' sempre visibile fino a che il tuo programma è in esecuzione.

Il perché di questa visibilità ( _app,  è un oggetto), risiede nel fatto che puoi usare proprietà custom di _app invece di variabili PUBBLICHE.

Ogni proprietà custom di _app sarà indirizzabile in tutto il tuo programma.

Diciamo che se stai scrivendo un programma, che ha solo una singola istanza per ciascuna scheda  Non ti devi preoccupare di usare un array oppure di sovrascrivere variabili di Istanza.

Puoi "attaccare" la tua Istanza di riferimento nell'oggetto _app di Visual dBase:

_app.oMyHelo = New Helicopter()

Adesso hai la garanzia che "oMyHelo" sarà "accessibile" in tutto il tuo programma, visibile a ogni oggetto, procedura e funzione.

E se hai bisogno di un array per memorizzare le tue Variabili di Riferimento all'istanza, puoi anche "attaccarle" nell'oggetto _app:

_app.aForms = New Array(1)

_app.aForms[1] = New Helicopter()

_app.aForms[1].Open()

dove anche sarà visibile a tutti oggetti, procedure e funzioni.

 

Rilasciare gli Oggetti

Gli oggetti "consumano" memoria. E non solo memoria "normale", ma risorse GDI, le quali sono molto scarse in Windows. La maggior parte "dell'economia domestica" (pulizia) è gestita automaticamente da  Visual dBase. Per esempio, quando in memoria non ci sono riferimenti ad un oggetto, Visual dBase distrugge l'oggetto per liberare memoria.

Puoi distruggere esplicitamente un oggetto in due modi:

1. Se hai un metodo Release(), chiamalo per rimuovere l'oggetto dalla memoria.

2. Distruggi la variabile di riferimento all'istanza (oggetto) e Visual dBase rimuoverà l'oggetto automaticamente.

Esempi:

oMyHelo.Release() && Chiama il metodo release

Release All Like oMyCustom &&Rilascia l'istanza di riferimento

_app.aForms[1] = '' && sovra scrive l'istanza di riferimento

Una volta che l'oggetto è rilasciato, non hai bisogno della definizione di classe in memoria . Rimuovila con:

Close Procedure Helicopter.WFM

Usare le Sessioni per Incapsulare

Sappiamo che le proprietà sono Incapsulate dentro i loro oggetti. Sappiamo altresì, che dobbiamo isolare la Variabile di Riferimento all'Istanza, prima che tu possa avere istanze multiple di un oggetto, per evitare sovra scritture.

Ma per le tabelle dati bisogna fare un altro discorso. Le tabelle sono  "accessibili"  nelle loro aree di lavoro - e non da qualche oggetto. Ancora, c'è un dato importante - il puntatore al record -  ha bisogno anche di essere incapsulato.

Presumi che il tuo utente visualizzi contemporaneamente tre schede Elicottero. Presumi, anche, che ciascuna scheda ha un oggetto Browse.

La scheda Numero Tre è in primo piano, quando l'utente clicca sulla barra di scorrimento,per cambiare il record attivo. A meno che, tu non faccia qualcosa per evitarlo, spostandosi su un altro record nella scheda elicottero tre, cambierà anche il record nella scheda elicottero due e elicottero uno.

Quindi, il puntatore al record deve essere incapsulato- protetto dal movimento del puntatore record in un altro oggetto elicottero.

Visual dBase, provvede con una caratteristica pulita, per gestire questa situazione, chiamata Sessioni (Session) .

Le Sessioni, essenzialmente creano un nuovo utente. Ciascuno utente, ha le proprie aree di lavoro, puntatori al record, aliases e variabili d'ambiente. Per creare una Sessione prima di lanciare un oggetto, incapsula la tabella dei dati in ciascuna scheda:

Procedure Helicopters_OnClick

Set Proc to Heli.Wfm Additive

_app.aForms[NextNum] = New HeliForm() &&Crea un nuovo oggetto e memorizza l'indirizzo in un elemento di un array

 Create Session    &&Crea una nuova sessione

Do Heli.Qbe         &&Apre la tabella richiesta 

&&Nota: questo può anche essere fatto usando la proprietà view della scheda

 _app.aForms[NextNum].Open() &&Apre la scheda.

Quando tutti i riferimenti alla tua scheda, sono rilasciati e rimossi,(non ci sono riferimenti oggetto), Visual dBase automaticamente chiude la Sessione.

Suggerimento: Non usare Create Session,  quando non vuoi incapsulare i dati.

Se hai una scheda figlia di controllo [lookup] dove vuoi che il puntatore al record cambi anche nella scheda genitore, non hai bisogno di incapsulare la scheda figlia.
In casi simili a questi, dove condividi i dati tra oggetti, non usare Create Session.

I Files .WFM, .CFM, .PRG e .CC

 Normalmente le schede sono nei files .WFM, le procedure nei .PRG, le queries nei QBE, controlli custom nei .CC , le schede "Superclass" nei .CFM.

Nota bene che le tue classi, possono essere dovunque tu desideri. Esse non saranno eseguite.

Set Procedure To <C:\ MyDiskFile> è sufficiente per Visual dBase per trovare la tua classe - tramite il nome. Perciò, ogni file su disco che può essere caricato in memoria con "Set Procedure To"  può contenere una definizione di classe.

Infatti ogni file caricabile può contenere diverse definizioni di classe !

Quando esegui  "Do My.Wfm"

Local f   &&questo codice viene eseguito

f = New MyForm()

f.Open()

CLASS MyForm of Form &&questo no!

...

...

ENDCLASS

 

Una definizione di classe, è solamente usata quando tu crei un'istanza - quando viene letto il codice "modello".

Perciò deve essere disponibile - in memoria - quando Visual dBase avrà  necessità di leggerla, per creare un oggetto.

Un esempio di una chiamata "diretta" ad un oggetto:

Procedure LookupButton_OnClick

Set Procedure to C:\MyDir\My.WFM Additive

Form.oLookup = New MyForm()

Form.oLookup.ReadModal() (or oLookup.Open())

Form.oLookup.Release()

Close Proc C:\MyDir\My.Wfm

 

Schede Modali: Emulazione del comportamento di "ritorno" alla procedura chiamante

Ricorderai che abbiamo affermato più di una volta che "gli oggetti non sono sottoprogrammi e non restituiscono (return) il controllo a nessuno". Bene, c'è un caso speciale: Le Schede Modali.

Le schede possono essere "non modali" o "modali". Normalmente lo stato di una scheda è non modale.

Una scheda non modale ha le seguenti caratteristiche:

Mentre la scheda è aperta, il fuoco può essere trasferito su altre schede. L'esecuzione della routine che ha aperto la scheda continua dopo che la scheda è stata aperta.

Le schede si aprono come finestre non modali quando si vogliono aprire più schede contemporaneamente. Ad esempio, un'applicazione che esegue numerose attività può usare una scheda diversa per ciascuna attività.

 Schede Non Modali:

Procedure HeliLookup_OnClick

Set Proc to HeliLook.Wfm Additive

_app.oMyHelo = New HeliLookForm()

_app.oMyHelo.Open() &&Apertura non modale.

Form.Entryfield1.Value = 'Hello' && questa linea viene subito dopo l'apertura della scheda

 

Una scheda aperta come finestra modale ha le seguenti caratteristiche:

Quando la scheda è aperta, il fuoco non può essere trasferito su altre schede.
L'esecuzione della routine che ha aperto la scheda si arresta finché la scheda non viene chiusa. Quando la scheda non viene chiusa, il controllo viene trasferito alla riga di comando successiva a quella che ha aperto la scheda.

Molte applicazioni usano le schede modali come finestre di dialogo, che di regola chiedono agli utenti di intraprendere un'azione prima che la finestra di dialogo possa essere chiusa.

Schede Modali:

Procedure HeliLookup_OnClick

Set Proc to HeliLook.Wfm Additive

_app.oMyHelo = New HeliLookForm()

_app.oMyHelo.ReadModal() && Apertura modale .

  Form.Entryfield1.Value = 'Hello' && alla chiusura di oMyHelo  viene eseguita questa linea.

Le schede non modali sono aperte con il metodo Open(). Le schede Modali sono aperte con il metodo ReadModal().

Se hai bisogno di aprire una scheda, che faccia qualcosa e poi ritorni "indietro", usa ReadModal(). Non usare questa capacità delle schede modali per emulare codice procedurale per aggirare OO, prima o poi ti ritroverai "inscatolato"!!! 

Pensando OOP - Tips

Ecco alcuni concetti rapidi per aiutarti a "Pensare OOP":

1. Creazione di Oggetti

A. File su disco caricato in memoria

B. Crea un nuovo Oggetto (Istanza)

C. Apri l'oggetto (nel caso di una scheda)

D. elimina l'oggetto

E. Scarica dalla memoria il file su disco.

2. Gli oggetti non "Ritornano" alle procedure che li hanno creati, così imposta le caratteristiche dell'oggetto prima che sia "lanciato" oppure incapsulale  nell'oggetto stesso.

3. Le schede possono essere basate su altre schede, i pulsanti (pushbuttons) su altri pulsanti.

4. Le schede possono "parlare" con altre schede solo se possono trovare ciascuna altra variabili di riferimento all'istanza.

5. Gli eventi si attivano automaticamente

per capire quando si attivano aggiungi ?? CHR(7) ai possibili eventi.

?? CHR(7) è il campanello che ti avvertirà quando un evento si è verificato.

6. Prova a creare una nuova scheda base (.CFM) metti un oggetto rettangolo ed un bel oggetto testo colorato quale titolo. Usa l'opzione FILE del menu in Impostazione Scheda e scegli "Imposta classe scheda custom". Adesso puoi creare nuove schede  basate sulla tua classe custom.

7. La cosa più importante: Non farti scoraggiare da OOP.

Può passare una settimana o un mese, ma uno giorno la  "lampadina" si accenderà sulla tua testa e comincerai pensare o sognare in questo nuovo linguaggio, e ne sarà valsa la pena quando scoprirai quanto ti farà essere produttivo OOP!

 9-1-1995