Aplicarea cadrelor pentru scrierea aplicațiilor "corecte"
Nu știu despre tine, dar în timpul meu am întâlnit adesea situația următoare. La dezvoltarea unor proiecte destul de mari, numărul de formulare a crescut cu timpul. Și mai departe, cu atât mai rău. Dar chiar și asta nu a fost o problemă mare, atâta timp cât m-am descurcat - cu toate acestea poți auto-disciplinat - să forțezi să folosești denumiri uniforme de forme, metode, variabile. Dar după ce am început să lucrez într-o echipă, problema a fost la maxim - refactorizarea a început să fie redusă pentru a "rescrie totul", pentru că fiecare programator a avut propria sa înțelegere a "codului corect scris". După unii gândiri am decis să creez un "motor" , ceea ce va facilita scrierea unor proiecte mari. În baza acestui motor, am pus astfel de principii:
1. Toate obiectele fără excepție pentru a lucra cu bazele de date trebuie să se găsească în modulele de date, iar numărul obiectelor din baza de date nu trebuie să depășească o anumită limită critică (pentru mine - până la 50 de obiecte) - este greu să navighezi mai departe;
2. Toate operațiunile de lucru cu datele din baza de date trebuie de asemenea descrise în module de date, în evenimente relevante sau în ActionList;
3. Formularul principal nu trebuie să conțină codul pentru lucrul cu moduri, doar un apel în mod și un apel de abstract, comun pentru toate metodele, care vor fi redefinite în fiecare mod corespunzător.
4. Interfața utilizator a tuturor modurilor trebuie să fie complet uniformă.
5. Modul trebuie să aibă "dreptul" de a schimba fereastra principală.
6. Modul nu ar trebui să știe despre existența altor moduri și a altor forme în general, numai forma principală și modulele de date ar trebui să fie disponibile pentru modul.
7. Modulele de date nu ar trebui să fie conștiente de existența modurilor.
8. Modurile ar trebui să fie create dinamic, pentru a nu consuma memorie inutilă.
Pentru punerea în aplicare a acestei sarcini, cadrele cele mai potrivite. Folosind cadre, a fost posibilă realizarea unei interfețe uniforme, deoarece Am avut o formă principală, pe care cadrele au fost pur și simplu schimbate - "cadre". Cu toate acestea, prima implementare a fost nereușită, deoarece pentru a lucra cu funcții specifice, a trebuit să fac toate cadrele pe forma principală și să trec între ele folosind proprietatea Visible.
În plus, codul formei principale a fost supraîncărcat cu funcții în care sa determinat modul în care este încărcat în prezent și, prin urmare, a fost apelată metoda dorită a modului.
Pentru că a fost decis să se îndepărteze de programarea procedurală a "moștenirii grele" :) și să se folosească de principiile de bază ale PLO.
Și într-adevăr, sa dovedit că toate cadrele pot (mai mult, aveți nevoie) pentru a face moștenitorii unor cadre de bază. Codul de bază este prezentat mai jos.
După cum puteți vedea, multe dintre funcțiile din cadrul de bază returnează o valoare de tip TFunctionResult. Această structură este definită în modulul UnitConstTypes_etc, în care vor fi adăugate alte tipuri și constante în viitor. Funcțiile returnează un semnalizator pentru finalizarea cu succes a operației și, dacă apare o eroare, textul mesajului de eroare.
Acest lucru, desigur, este un șablon. În aplicațiile mele curente, funcțiile de mai sus sunt mai mult decât suficiente. Cu toate acestea, dacă trebuie să adăugați o anumită metodă specifică, nu există nici o dificultate în acest sens.
În plus, în procedura de export de date, se numește metoda SaveToHTML a grilei actuale a cadrului. Această metodă este definită în modulul MyDBGrid.
Să trecem la afișarea cadrelor pe formularul principal al aplicației.
Principalele forme de aplicații pe care le am în acest fel: în stânga - arborele meniului, în partea de jos a jurnalului de aplicații, în partea de sus - bara de instrumente, restul spațiului este gol, este ocupat de panoul pe care vor fi afișate cadrele.
În primul rând, vom crea propriul nostru tip
Acum trebuie să creați o formă principală de lucru. În utilizări adăugăm modulul UnitFrameBase, în secțiunea publică inserăm obiectul MainFrame din clasa TFrameBase. Acum trebuie să scriem o funcție care să afișeze corect cadrul dorit când deschideți modul dorit.
Cum pot numi această funcție? Creați un mesaj suplimentar - pentru a apela procedurile de filtrare.
Param1 și Param2 sunt folosite pentru a genera interogările dorite în același tip de cadre. Acum trebuie să scriem mesajul handler pentru mesajul FILTER_EVENT.
Vom trece la afișarea cadrului meniului. Ca un fișier XML sursă puteți utiliza structura meniului de stocare arbore (acest lucru este util în cazul în care cererea nu utilizează o bază de date), tabelul de utilizare în baza de date de aplicare sau de a menține structura direct în aplicația (foarte convenabil de a face acest lucru în dxTreeList de la DevExpress, dar aceste componente sunt plătite) . Deoarece toate aplicațiile mele de baze de date utilizate (Oracle sau Firebird SGBD cea mai mare parte), am ales a doua opțiune. Crearea unui tabel cu următoarea structură
În plus, pentru a asigura integritatea copacului, mai multe declanșatoare și constrângeri sunt asociate cu tabelul. Complet structura tabelului și textul restricțiilor pe care le puteți vedea în textul sursă al bazei de date.
Din această masă relațională este destul de ușor să creați un copac cu ajutorul unei proceduri recursive, textul căruia să-l puteți arăta și în textul sursă al bazei de date. Rețineți că principiile pentru crearea unei astfel de proceduri sunt luate din cartea "World of InterBase".
Fără a intra în detaliile construirii unui copac pe server, rețineți că în aplicația client puteți construi un copac într-o singură trecere a setului de date.
Procedura de afișare a copacului este prezentată mai jos. În primul rând, definim structura elementelor de meniu
Firește, structura elementului de meniu este aceeași cu structura tabelului din baza de date. Creați meniul cu următoarea funcție
Funcția de schimbare a elementelor din meniu va avea următorul aspect
În mod similar, pentru alții. În plus, în forma principală, trebuie să creați și elemente comune pentru filtrare. Ele pot fi elemente de filtrare după date, conturi etc. Cu toate acestea, în handler, modificările la aceste elemente trebuie să trimită doar un mesaj CX_FILTER. Modul de procesare a mesajului primit va rezolva un cadru specific.
În plus față de cele de mai sus, formularul principal va trebui să înregistreze toate tipurile de cadre. Acest lucru se face în secțiunea de inițializare a funcției RegisterClasses.
Acum trebuie să creăm cadre. Cadrul trebuie să moștenească din cadrul abstract TFrameBase creat mai sus. După aceasta, trebuie să redefiniți modurile necesare.
În cel mai simplu caz, trebuie să suprascrieți constructorul de cadre, la care redefiniți descrierea cadrului apelând SetDesc și stabilind setul de date cadru cadru prin apelarea SetFrameCurrentDataSet. Dacă există o grilă pe cadru, atunci trebuie să înlocuiți funcția GetMainGrid, astfel încât să returneze funcția dorită.
Astfel, pentru a adăuga un nou mod în cel mai simplu caz, trebuie să scrieți doar 9 linii de cod!
Cu toate acestea, schimbarea (îmbunătățirea) cadrului absolut nu duce la nici o editare a formei principale. Funcțiile de lucru cu datele sunt cauzate numai de metodele de date corespunzătoare. La manipulator pot fi chemați forme suplimentare sau dialoguri modale.
Codul aplicației de testare care demonstrează lucrarea descrisă cu cadre este aici.