Implementering av virksomheten objects

Klasser som innkapsler forretningsregler legge grunnlaget for en sann objektorientert application.Implementing Forretnings ObjectsThis artikkelen er den første av en serie der vi skal utforske de mange fasetter av å implementere en sann objektorientert program. Underveis vil vi ta i nesten alle aspekter av program design og utfordre noen av de aksepterte måter å skrive en Delphi program. Det grunnleggende konseptet bak denne tilnærmingen er innkapsling: å utforme et sett med klasser med godt definerte grensesnitt (metoder) som opererer på eiendommer. Disse begrepene vil gjennomsyre hele programmet, og vil i stor grad påvirke hvordan data blir lagret og presentert. Jeg ville anbefalt leserne å studere Francis Glassborow sin C ++ kolonne; selv om Delphi objektmodellen mangler fullstendighet (og kompleksitet) av C ++, begrepene godt førsteklasses design er uavhengige av language.Most typiske Delphi applikasjoner skrevet i dag er ikke objektorientert. Bare fordi språket har en objektmodell og mange eksisterende og nye klasser er brukt, betyr ikke dette at søknaden kan betraktes som virkelig OO. Gjenbruk av kode er ferdig med å slippe tredjepartskomponenter på skjemaer og avhengighetsforhold mellom former og enheter raskt sprer. Fremtidige muligheter for å endre programgrunnleggende (for eksempel bytte database eller flytting fra to-lags til gjennomføring tre-lags) er sterkt begrenset eller svært kostbart å tenke på. Skrive søknad i en ekte OO mote ville lette, snarere enn å begrense disse mulighetene. Men å skrive slike søknader krever en tanke skift, ledsaget av en innledende mangel på produktivitet, at de fleste utviklingsteam er uvillig eller ute av stand til å vurdere. I løpet av disse artiklene jeg håper å demonstrere noen av de grunnleggende som vil hjelpe utviklere få flytte til implementering av bedre programmer. De resulterende systemer vil alltid være mer pålitelig, vedlikeholde, konsekvent, fleksibel, gjenbrukbare og generelt bedre resultater enn et program skrevet på vanlig måte. Spesielt fordelene med kode klarhet er slik at for store programmer, ett skrevet i en virkelig OO mote kan kreve betydelig mindre ressurser vedlikehold enn samme program skrevet tradisjonelt. Jeg burde kanskje rettferdiggjøre disse fordelene med en OO-programmet videre: Jeg tror at noen IT talsmenn med noe å selge (i dette tilfellet en visjon om bedre programmer) bør komme unna uimotsagt Den forbedrede påliteligheten av OO søknader kommer fra det faktum at data og operasjoner er innkapslet i veldefinerte klasser. Kompilatoren selv vil oppmuntre riktig klasse, metode og eiendom bruk gjennom sterk type kontroll, og har unik snarere enn duplisert kode betyr at fremtidige endringer i en enkelt rutine er gjennomgående i hele programmet. En konsekvens av riktig bruk av klasser er at relasjonene mellom dem er selvinnlysende og en langt større del av koden er skrevet er faktisk gjennomføringen av "kjøtt" på programmet, heller enn å bekymre detaljer som hvordan data er faktisk lagret vedvarende. Dette gjør applikasjonen betydelig enklere å vedlikeholde, en faktor ytterligere forenkles ved større konsistens gjennom. Som vi skal se, ved hjelp av klassen arv mye både øker produktiviteten og pålitelighet, men pålegger også konsistens. Dette konsistens er tydelig på den måten at koden er lagt ut og hvordan klasser oppføre seg, men også i den grad av hvordan data blir lagret og hvordan brukergrensesnittet er presentert. Så mye av funksjonaliteten er gitt i grunnklasser, er det mulig å raskt endre sin atferd for å fundamentalt påvirke programmet (for eksempel endring av grensesnitt for å være html-basert, heller enn form drevet). Disse grunnklasser kan være utformet for å være uavhengig av applikasjon, slik at det andre program skrevet på denne måten oppnår en umiddelbar produktivitetsøkning. Et godt sett med grunnklasser kan gi opp til 50% av koden i en middels stor anvendelse, en åpenbar fordel fra en tid, kostnad og pålitelighet stående. Det er bare rimelig å markere at det å gjøre overgangen til "ekte" OO utvikling er ikke trivielt, og bør bare foretas for første gang med erfaren assistent eller for et prosjekt av liten størrelse uten haster tidsfrister. Det bør også understrekes at en OO løsningen ikke diktere andre klasser som må (eller må ikke) brukes i programmet. Hvis et selskap har utviklet sine egne visuelle komponenter, bruker de av en tredjepart, eller har standardisert på en bestemt database plattform så er det ingen grunn til at disse ikke kan brukes (med en betydelig unntak). Utvikle en OO-programmet handler om å bruke et konsistent sett av design patterns heller enn å diktere hvilke komponenter som skal brukes. Fokusert klasser
Det første trinnet i å utforme et objekt-orientert programmet er å tenke på de klassene som vil være nødvendig. Dette er en helt grunnleggende trinn, som med alle andre utvikling teknikk, som får det galt på et tidlig stadium vil være kostbart å korrigere. I utformingen våre klasser bør vi generelt strever for lav kobling og høy samhold - klasser bør være så uavhengig som mulig fra andre klasser, men bør være mulig å kombineres på effektive måter. En måte å oppnå dette på er å kategorisere sett av klasser av rollene som de vil ha i programmet. Skjønnsomt valg av disse rollene vil resultere i et sammenhengende sett av classes.There er en grunnleggende regel som går igjen i hele klassen rolle design: sterk separering av de klasser som er ansvarlige for presentasjon, påføring og utholdenhet. Presentasjon kan generelt tatt som brukergrensesnitt, og utholdenhet som noe som lagrer data (typisk i en database). Selv om dette er den samme separasjons som eksisterer for utvikling av tre-lags, bør det bemerkes at dette er en konstruksjons- separasjon som kan implementeres på mange måter: som en enkelt monolittisk påføring hele veien gjennom til en fullstendig distribuert multi-lags-systemet . Settet med klasser som inngår i programmet logikken er de som faktisk gjør det harde arbeidet med å svare på bruker stimuli for å manipulere og behandle data. En undergruppe av klasser innenfor dette laget er identifisert som representerer den virkelige verden enheter som vil bli modellert av systemet. Disse er svært ofte stemplet som "business" eller "problem domene" klasser. De utgjør en viktig del av enhver OO system, som de fleste andre klasser kommer til å støtte dem på en eller annen måte, og de danner fokus for alle utvikler involvement.Identifying Business Objects for en gitt applikasjon generelt blir instinktiv med erfaring, selv om det er en hel vitenskap (eller er det kunst?) bak prosessen. Det fine med OO sammenlignet med tradisjonelle teknikker som SSADM er at prosessene for analyse og design som har utviklet seg opprettholde de samme enhetene gjennom: det er mulig å se en representasjon av hver enkelt bedrift objekt gjennom OOA (analyse), OOD (design) og til slutt selve gjennomføringen (OOP). Vi vil utforske noen av teknikkene for å identifisere de riktige forretningsobjekter i fremtidige kolonner. For tiden blir, vil vi anta at disse prosessene har vært performed.The kommunikasjon mellom klasser som finnes i de forskjellige lagene (presentasjon, søknad, utholdenhet) er veldefinert og bør følges helt. Dette er vist i figur 1, og pilene indikerer at en klasse i ett lag kan foreta metodekall i en annen klasse. Dette diagrammet viser at presentasjonen laget (brukergrensesnittet) kan manipulere applikasjonslaget eller andre klasser i brukergrensesnittet, og at applikasjonslaget (Business Objects) kan manipulere seg selv og ringe inn i utholdenhet lag, som bare kan svare på forespørsler fra applikasjonslaget. Business Objects
å demonstrere hvordan forretningsobjekter kan gjennomføres, vil vi følge en jobbet eksempel med et lite sett av klasser utsette de klassiske Stock, kunde- og ordre enheter (et selskap tilbyr en antall elementer på lager for salg, som kan kjøpes (bestilles) av kunder). Våre (triviell) analyser har bekreftet at i utgangspunktet vil vi bli som krever tre forretningsobjekter til å representere hver av disse enhetene. I vår Delphi søknad vil vi ha tre klasser: TStockItem, TCustomer og TOrder. Listing 1 viser en forkortet felles grensesnitt for disse klassene. Det bør bemerkes at alle egenskapene av den klasse som er utsatt egenskaper: dette er ganske enkelt god klasse utforming og muliggjør kontroll over adgang til egenskapene (bør dette være nødvendig). Det bør også bemerkes at egenskapene blir eksponert i den publiserte delen av klasse (av grunner vil vi diskutere i fremtiden), og at de er fullstendig med standardverdier der det passer. Selv om denne egenskapen kvalifiseringen er tilsynelatende brukes når streaming komponenter, det tjener en nyttig hensikt å betegne den opprinnelige verdien av hver eiendom og hjelper koden for å være selv descriptive.Something som er grunnleggende for virksomhet (problemdomenet) objekter er at de kan ha ingen kunnskap om hvordan de er lagret vedvarende. De vet ikke hvordan de er lagret i databasetabeller, faktisk kan de gjøre absolutt ingen forutsetninger om lagring hodet. En virksomhet objektet er en svært fokusert klasse som eksponerer bare passende egenskaper og metoder som er nødvendig for å manipulere dem. Ved utforming av felles grensesnitt av klassen ingen konsesjon bør gjøres med hensyn til hvilke typer egenskapene for vedvarende (database) lagring. Du bør alltid velge den mest passende type for den aktuelle eiendommen, uavhengig av hvorvidt den tiltenkte database støtter dem smertefritt. Et godt eksempel er et sett egenskap: Noen databaser støtter sett direkte, men hvis dette er en naturlig måte å utsette en eiendom av en virksomhet objekt så det bør velges fremfor en annen representasjon (muligens en rekke Booleans). Et annet eksempel er å eksponere noe sånt som en adresse som et TStringList. Det er ikke den rollen av virksomheten objekt å skade det er grensesnittet for å favorisere datalagring: dette er oppgaven til utholdenhet laget Vår første rammeverk
Vi har identifisert og gjennomført tre forretningsobjekter som startgrunnlag for vår. søknad. Disse tre stedene har en felles rolle: å representere reelle enheter på noen måte. Vi forventer derfor at de skal ha tilsvarende egenskaper, og derfor en klassehierarkiet er hensiktsmessig. Vi vil gi hver av disse objektene en felles stamfar, kalt TPDObject (for Problem Domain objekt). Dette TPDObject klassen vil bli utvidet etter hvert som vi innføre felles metoder og egenskaper til våre klasser. Det bør bemerkes at TPDObject ikke inneholder (og aldri vil) alle applikasjonsspesifikke elementer. Som et program-uavhengig konstruksjon bør den plasseres i en egen enhet og danner grunnlaget for et rammeverk: et sett av klasser som kan gjenbrukes i mange applikasjoner. Over tid vår rammeverk vil ekspandere i stor grad til å gi mange grunnklasser som gir vesentlig uavhengig av applikasjon funksjonalitet, klar til å være spesialisert for bestemte systemer. Våre TStockItem, TCustomer og TOrder klasser er eksempler på spesialiserte versjoner av vår generiske TPDObject. En nærmere undersøkelse av Listing 1 viser at, faktisk, våre tre problem domene klasser hver stammer fra en annen klasse, TMyAppPDObject, selv en etterkommer av TPDObject. Selv om gjennomføringen av TMyAppPDObject er tom, er det nok et eksempel på god klasse design, slik at hvis vi ønsker å gi noen programspesifikke elementer til alle våre problem domene objekter det er en passende klasse i vår hierarchy.Listing 2 viser vår embryonale Work enhet. I øyeblikket er TPDObject klassen gir bare en skrivebeskyttet egenskap kalt ID, som er av typen TObjectID. Denne egenskapen blir brukt til å gi hver klasse begrepet identitet: Det vil vi definere to forekomster som representerer det samme objektet hvis de er av samme type og har samme ID verdi. Dette har med hensikt blitt definert som det egne type, slik at det ikke er direkte tilordning er kompatibel med andre skalare typer. Valget av type for TObjectID er vilkårlig: Jeg har valgt i dette tilfellet for å gjøre det til et heltall type, men det er en sak for å gjøre det en egen klasse. Selv om en mer "ren" tilnærming, har jeg besluttet mot dette på grunnlag av at våre problemdomene objekter vil bli bygget (og ødelagt) mange tusen ganger i løpet av en søknad og vi kan unngå overhead av å bygge og ødelegge den ekstra TObjectID klasse ( min purist argument for denne implementeringen valget er at den separate TObjectID klassen har blitt subsumert inn i TPDObject klassen som et sammensatt objekt). Det er et par ekstra metoder i denne enheten for å konvertere vår objekt identitet type til en streng representasjon, og en konstant for den første "har ingen identitet" verdi.Det er en rekke skoler med tanke på objekt identitet; sier at alle forretningsobjekter bør tildeles en identitet når det er konstruert og at identiteten må være unikt i et program (eller globalt som i en GUID). I praksis er det viktig bare å være i stand til å skille mellom to objekter i en gitt sammenheng, og holde denne enkle har åpenbare ytelse og lagring fordeler, selv om du absolutt ikke vil finne meg argumenterer mot et valg for en mer kompleks type i passende omstendigheter. et spørsmål om etikk
for å fremheve noen av de utforming og implementering beslutninger som tas når du utformer et rammeverk jeg vil ved behov stille spørsmål, og inviterer leserne til å vurdere begrunnelsen bak dem. I begynnelsen av kolonnen antydet jeg til en betydelig unntak til utsagnet om at en virkelig OO design ikke forbyr bruk av bestemte klasser. Hva er unntaket til denne uttalelsen (hint: svaret ligger innenfor figur 1). (((Oppføring 1 - En programspesifikke Problem Domain enhet (forkortet)))) enhet ProblemDomain, interfaceuses Work, skriver TMyAppPDObject = klasse (TPDObject) ende; TStockItem = klasse (TMyAppPDObject) publisert eiendom Navn: String; Eiendommen QuantityInStock: Cardinal standard 0; Eiendommen TradePrice: Valuta; Eiendommen RetailPrice: Valuta; slutt; TCustomer = klasse (TMyAppPDObject) ...; . TOrder = klasse (TMyAppPDObject) ...; implementationend (((End Oppføring 1))) (((Oppføring 2 - Et program uavhengig Work enhet))) enhet Work; interfaceconst NotAssigned = 0; typen TObjectID = typen Integer; TPDObject = klasse privat FID: TObjectID; offentlig eiendom ID: TObjectID lese FID standard NotAssigned; enden, funksjon StrToID (Verdi: String): TObjectID; funksjon IDToStr (Verdi: TObjectID): String, implementering ... end (((End Oppføring 2))) (((Figur 1 - Class samhandling oversikt))) (. ((End figur 1))) Neste i serien