Fabrikk mønstre for menyen operations

I denne artikkelen jeg trykker på Factory mønster i tjeneste for menyen operations.Are Du blir servert i denne artikkelen tar vi en kort pause fra påkjenningene ved implementering av forretningsobjekter å forholde seg til noe som nesten alle bruksområder krever:? En meny. Ikke en meny i den forstand at en TMainMenu derivat, men snarere en slags front-end som viser en rekke tilgjengelige alternativer og krever en å bli valgt av brukeren. Et typisk eksempel vil være en liste over alternativer som presenteres for brukeren når et program starter: de er pålagt å velge om du vil starte den viktigste applikasjonen, eller kanskje den rapporteringspakke, generelle verktøy eller admin systemer. Disse alternativene er vanligvis presenteres for brukeren i ganske grove måter, kanskje et lite skjema med en rekke knapper hver med en bildetekst som beskriver programmet som skal kjøres, eller en listeboks med et antall oppføringer. Oftest disse meny-type former er hard kodet og egentlig "vet" hvordan å starte det valgte alternativet. Slike løsninger har to egenskaper: de er lite fleksible og lite tiltrekkende. Denne måneden vi bruker Factory mønster (og veloverveid valg av visuelle komponent) for å gi en bedre løsning. Kommer til å jobbe
En fabrikk mønster bør brukes når "en klasse ikke kan forutse klassen av gjenstander det må lage". Egentlig et klientobjekt bruker egenskapene og metodene for et abstrakt stamfar objekt, mens i virkeligheten er det å manipulere konkrete etterkommere som har blitt levert av klassen fabrikken. Nøkkelen til design er at kunden ikke trenger å vite noen spesifikke detaljer om selve objektene det er å manipulere, unntatt de som de deler i deres felles stamfar. Dette løsriver effektivt slike klasser ved kompilering. Med hensyn til vår nødvendige menyskjermen i Delphi, betyr det at menyen skjemaet ikke trenger å bruke enhetene som inneholder skjemaer som skal vises når en bestemt menyelement er valgt. Dette eleganse gir oss muligheten for å plassere slike former inni DLL-er, som er dynamisk lastet når bruken velger riktig menyvalg. Dette har de åpenbare fordelene ved minneforbruket (bare menyvalget aktivt valgt av brukeren under kjøring bruker minne), og at søknaden kan bli utvidet ved ganske enkelt å levere en ny DLL - eksisterende menyskjermen kan bare oppdage sin tilstedeværelse og legge den til listen presentert for user.Initially, vil vi vurdere tilfelle av en statisk bundet sett i menyfunksjoner; som er, vil alle tilgjengelige operasjoner bli utarbeidet i programmet. Vær imidlertid oppmerksom på at dette er rett og slett en praktisk; menyskjermen selv har fortsatt ingen eksplisitt kunnskap om virksomheten er tilgjengelig, eller hvordan de er koblet inn i applikasjonen. I stedet vil hver meny drift registrere seg med fabrikken og menyen skjemaet vil avhøre fabrikken for de tilgjengelige oppføringer. Menyen formen er da fritt til å presentere disse oppføringene på noen måte det ser passe. Når brukeren velger en menyoppføring, fabrikken bedt om å konstruere en konkret forekomst av den aktuelle typen, og dette er da displayed.The fabrikken selv har et veldig enkelt grensesnitt. Den har en metode som kalles Register som brukes av menyvalgene selv å varsle fabrikken av deres eksistens (jeg har brukt Register som det etterligner nomenklatur brukes av andre fabrikker i Delphi seg selv, slik som registreringen av komponenter for visning i komponenten palett). I tillegg har fabrikken to egenskaper som lar en annen klasse observere antall medlemmer i fabrikken, og gir tilgang til hver. Oppføring 1 viser en fullstendig iverksettelse av denne factory.We nå må legge til noen menyoperasjoner til fabrikken. Dette er veldig enkelt: lage noen nye former, legger MenuActionFactory enheten til bruk klausul i gjennomføringen delen, og legge til følgende kode i foten hver form enhet: initialisering MenuActions.Register (TMyNewForm), The TMyNewForm referansen bør erstattes med klassen navnet på den spesielle form for den aktuelle enheten. Nå som klassen vår fabrikk har blitt initialisert, kan vi slå våre sinn til hvordan det kan brukes. A la carte menyer
Som tidligere observert, mange "opplagte" måter å kreve at brukeren velge ett valg fra mange er visuelt tiltalende. En vertikal liste med brede knapper (med lange bildetekster) er en spesielt skjemmende, men overraskende vanlig løsning. Tenk på hvordan Windows løser et lignende brukergrensesnitt problemet: Kontrollpanel er et godt eksempel på en liste over ulike operasjoner. Dette er noe mer enn en listevisning, men et sett av godt utformet ikoner og konsekvent layout går en lang vei å tilby et attraktivt grensesnitt. Legg til dette innebygd evne til listevisning for å omorganisere det er ikoner som det er endret, og for å vise ikoner i forskjellige størrelser eller et mer beskrivende rapport visning, og du har en nesten ideell utvalg tool.To opprette en ny menyskjerm , slippe en listevisning på et tomt skjema og justere den til klientområdet. Jeg liker å slippe en TCoolBar topp-linje på skjemaet og legge til et par flate knapper (ved hjelp av bilder rippet fra Explorer) for å tillate brukeren å endre ViewStyle av listevisning. For å gjøre listen visningen automatisk ordne ikoner, legg til følgende kode i FormResize hendelsen: lvwForms.Arrange (arDefault); slutt må vi legge til et bilde liste til skjemaet og koble den til listevisning LargeImages property.we nå må vise menyalternativene som er tilgjengelige i fabrikken innen listevisning. Dette innebærer sykling gjennom de registrerte menyalternativer og opprette en ny listeelement for hver. Hvert element i listen må bli tildelt et bilde indeks for deres ikon, og en bildetekst - disse vil bli tatt direkte fra de samme navngitte egenskapene fra registrert form. Det er mulig å legge til ytterligere informasjon til menyelementer for eksempel når listevisning er i vsReport modus; det kan være en god idé å legge en lang beskrivelse vises som en annen kolonne, slik at uerfarne brukere kan få en bedre forståelse hva hver handling gjør. Et godt eksempel på dette kan sees i Management Console for Windows 2000. Nøkkelen til denne prosessen er at menyen presentasjonsform selv må bare bruke den MenuActionFactory enheten selv, og ingen av de spesifikke menyvalget former. Disse spesialiseringer er helt skjult inne i fabrikken; som navnet tilsier det vil skape en konkret klasse av riktig type, uten kundens noen gang ønsker å vite det nøyaktige detaljene. Oppføring 2 viser koden er nødvendig for å fylle listevisning. Legg merke til at som det sykluser gjennom hver registrerte menyen handling, skaper fabrikken den nødvendige klassen. Menyen formen skaper deretter en ny liste elementet med relevant informasjon før ødelegge objektet. Merk at for at dette skal fungere korrekt Constructors på de registrerte klassene må være virtuelle; dette er allerede gjelder for visuelle komponenter for eksempel skjemaer (fordi Delphi bruker en fabrikk for å lage dem så de blir streamet fra .DFM filer og ressurser), men for tilpassede klasser vil det være nødvendig å innføre en virtuell konstruktør i sin klasse hierarki. når dette skjemaet presenteres for brukeren og et element er valgt ved å dobbeltklikke, så kan vi igjen spørre vår fabrikk for å skape den spesifikke formen som kreves, som deretter kan vises. Det er absolutt ingen begrensninger om hva disse formene kan gjøre, men elegansen av fabrikken mønsteret er at klienten av fabrikken kan forbli uvitende om detaljene. Ytterligere menyalternativer kan legges inn i et utviklende system rett og slett ved å skape en ny form og registrere dem med fabrikken - de vil umiddelbart bli lagt inn i menysystemet neste gang programmet kjøres. Denne mangelen på kobling mellom elementene i systemet letter sterkt søknad vedlikehold for store prosjekter - bare ved å registrere klasser med en fabrikk utbygger vet at noen del av programmet som har en interesse i slike ting vil være updated.It er lett å se hvordan denne menyen løsningen er, i seg selv, generisk og kan brukes på en rekke applikasjoner, eller til og med den samme applikasjonen en rekke ganger. I mange av programmene mine har jeg en hovedmeny som viser alle de store moduler i programserien, to slike moduler blir rapportering og generelle verktøy. Når disse spesielle modulene er valgt de i sin tur viser en ytterligere meny av rapportene og verktøy som finnes i systemet hhv. Alle disse meny danner aksje koden gjennom visuell form arv, forskjellige kun i fabrikken som de bruker (det er forskjellige fabrikker for moduler, rapporter og verktøy). Den visuelle formen stamfar deles av alle tre kan være ganske funksjonell, dynamisk og legger TMenuItem oppføringer til programmet for hvert menyalternativ. Nøkkelordet her er gjenbruk av kode gjennom løs kopling - en stor fordel av objektorienterte prinsipper. Til sammenligning den tradisjonelle tilnærmingen av tett kopling de unike meny skjemaer til deres spesifikke meny handlinger ser lite fleksibel og uhåndterlig. Siste artikkelens problem
Sist artikkelen har vi diskutert hvordan en delegat objekt kan gis til å vedvare forretningsobjektinformasjon, og spørsmålet ble stilt, hvor kan denne bestemmelsen skje? Det åpenbare svaret på spørsmålet er å skape data management objektet i konstruktøren av virksomheten objekt: konstruktør TMyPDObject.Create; begynne arvet; //Pass nødvendig informasjon for å konstruktør DMObject: = TMyDMObject.Create; ende; Problemet med denne tilnærmingen er at hver bedrift objekt skaper vi har overhead for å konstruere en data management objekt. Avhengig av databasen, kan dette være en dyr operasjon, og derfor svært uønsket, spesielt når det anses at mange forretnings objekter vil bli bygget og ødelagt når programmet kjører. Ved å undersøke grensesnittet til klasse, kan det sees at last og lagre metoder er statsløse - alt arbeid er oppnådd i det ene metodekallet. Derfor, forutsatt at søknaden ikke krever multi-threaded databaseaktivitet i separate deler av problemet domene, kan en enkelt dataadministrasjon objekt deles blant de mange forekomster av Business Objects den kan håndtere. Enda bedre, kan dette datastyring objekt opprettes når programmet startes (eller første gang det er nødvendig). Disse data management objekter kan opprettes som private globale objekter i gjennomføringen delen av problemet domene, eller, mer elegant, en fabrikk kan brukes til å knytte data management klasser med forretningsobjektklasser og opprette dem på riktig måte (((Oppføring en. - en gjennomføring av en fabrikk for menynavigering))) enhet MenuActionFactory; interfaceuses Klasser, former; typen TMenuAction = TForm; TMenuActionClass = klasse av TMenuAction; TMenuActionFactory = klasse privat MenuActionList: tListe; funksjon GetCount: Integer; funksjon GetMenuAction (Indeks: Integer): TMenuAction; offentlig konstruktør Opprett; destructor Destroy; styre; Prosedyren Register (MenuActionClass: TMenuActionClass); Eiendommen Count: Integer lese GetCount; Eiendommen MenuAction [indeks: Integer]: TMenuAction lese GetMenuAction; misligholde; end; Var MenuActions: TMenuActionFactory; implementationconstructor TMenuActionFactory.Create, begynner arvet; MenuActionList: = TList.Create; ende; destructor TMenuActionFactory.Destroy, begynner MenuActionList.Free; arvet; end; funksjon TMenuActionFactory.GetCount: Integer; begynne Resultat: = MenuActionList.Count; ende; funksjon TMenuActionFactory.GetMenuAction (Indeks: Integer): TMenuAction; begynne Assert ((Indeks > = 0) og (Index < Count) 'Index utenfor rekkevidde.'); //Konstruer og returnere den valgte oppføringen Resultat: = TMenuActionClass (MenuActionList [Indeks]) Opprett (null); end; prosedyre TMenuActionFactory.Register (MenuActionClass: TMenuActionClass.), Begynner MenuActionList.Add (MenuActionClass); end; initialisering MenuActions: = . TMenuActionFactory.Create, sluttbehandling MenuActions.Free, slutten (((End Oppføring 1))) (((Oppføring 2 - Ved hjelp av en fabrikk for å fylle en listevisning))) prosedyre PopulateListView (lvwMenu: TlistView; Factory: TMenuActionFactory); Var Indeks: Integer; MenuAction: TForm; begynne for indeks: = 0 til Factory.Count - en ikke begynne MenuAction: = Factory.MenuAction [Indeks]; med lvwMenu.Items.Add gjøre begynne Caption: = MenuAction.Caption; ImageIndex: = lvwMenu.LargeImages.AddIcon (MenuAction.Icon); SubItems.Add (MenuAction.Hint); slutt; end, end, (((End Oppføring 2))) Neste i serien