Programmering

Smartere Java-udvikling

En hurtig og enkel ordning til at fremskynde udviklingen af ​​store Java-applikationer involverer brug af grænseflader. Java-grænseflader er en plan for funktionaliteten i et tilknyttet objekt.

Ved at integrere grænseflader i dit næste projekt vil du bemærke fordelene gennem hele udviklingsindsatsens livscyklus. Teknikken til kodning til grænseflader snarere end objekter forbedrer effektiviteten af ​​udviklingsteamet ved at:

  • Tillader udviklingsholdet hurtigt at etablere interaktionen mellem de nødvendige objekter uden at tvinge den tidlige definition af de understøttende objekter
  • Gør det muligt for udviklere at koncentrere sig om deres udviklingsopgaver med den viden, at integration allerede er taget i betragtning
  • Tilvejebringelse af fleksibilitet, så nye implementeringer af grænsefladerne kan tilføjes til det eksisterende system uden større kodemodifikationer
  • Håndhævelse af de kontrakter, der er aftalt med medlemmer af udviklingsteamet for at sikre, at alle objekter interagerer som designet

Et overblik

Fordi objektorienteret udviklingsindsats involverer interaktioner mellem objekter, er det vigtigt at udvikle og håndhæve stærke kontrakter mellem disse objekter. Teknikken til kodning til grænseflader involverer brug af grænseflader snarere end objekter som den primære kommunikationsmetode.

Denne artikel introducerer brugeren til begrebet kodning til grænseflader gennem et simpelt eksempel. Et detaljeret eksempel følger, som hjælper med at demonstrere værdien af ​​denne ordning i et større system, der kræver flere udviklere. Før vi kommer til prøvekoden, lad os dog se på fordelene ved kodning til grænseflader.

Hvorfor kode til grænseflader?

Java-grænsefladen er en udviklingskontrakt. Det sikrer, at et bestemt objekt opfylder et givet sæt metoder. Grænseflader bruges i hele Java API til at specificere den nødvendige funktionalitet til objektinteraktion. Eksempler på brug af interface er tilbagekaldsmekanismer (Begivenhedslyttere), mønstre (Observer) og specifikationer (Kan køres, Serialiserbar).

Kodning til grænseflader er en teknik, hvor udviklere kan udsætte bestemte metoder for et objekt til andre objekter i systemet. Udviklerne, der modtager implementeringer af disse grænseflader, har evnen til at kode til grænsefladen i stedet for kodning til selve objektet. Med andre ord ville udviklerne skrive kode, der ikke interagerede direkte med et objekt som sådan, men snarere med implementeringen af ​​objektets grænseflade.

En anden grund til at kode til grænseflader snarere end til objekter er, at det giver højere effektivitet i de forskellige faser af et systems livscyklus:

  • Design: metoderne til et objekt kan hurtigt specificeres og offentliggøres for alle berørte udviklere
  • Udvikling: Java-kompilatoren garanterer, at alle metoder til grænsefladen implementeres med den korrekte signatur, og at alle ændringer i grænsefladen straks er synlige for andre udviklere
  • Integration: der er evnen til hurtigt at forbinde klasser eller undersystemer på grund af deres veletablerede grænseflader
  • Testning: grænseflader hjælper med at isolere fejl, fordi de begrænser omfanget af en mulig logisk fejl til en given delmængde af metoder

Der er noget overhead forbundet med denne udviklingsteknik på grund af den nødvendige kodeinfrastruktur. Denne infrastruktur inkluderer begge grænseflader til interaktionen mellem objekter og indkaldelseskode for at skabe implementeringer af grænseflader. Denne omkostning er ubetydelig sammenlignet med den lette og fordel ved at bruge grænseflader som beskrevet.

Grundlæggende eksempel

For yderligere at forklare begrebet kodning til grænseflader har jeg lavet et simpelt eksempel. Selvom dette eksempel klart er trivielt, viser det nogle af de fordele, der er nævnt ovenfor.

Overvej det enkle eksempel på en klasse Bil der implementerer interface Køretøj. Interface Køretøj har en enkelt metode kaldet Start(). Klasse Bil vil implementere grænsefladen ved at levere en Start() metode. Anden funktionalitet i Bil klasse er udeladt af hensyn til klarheden.

interface Vehicle {// Alle køretøjsimplementeringer skal implementere startmetoden offentlig ugyldig start (); } klasse bilimplementerer køretøj {// Krævet for at implementere køretøjets ugyldige start () {...}} 

Efter at have lagt grundlaget for Bil objekt, kan vi oprette et andet objekt kaldet Betjent. Det er Betjentjob til at starte Bil og bringe det til restaurant protektor. Det Betjent objekt kan skrives uden grænseflader som følger:

klasse Betjent {offentlig bil getCar (bil c) {...}} 

Det Betjent objekt har en metode kaldet getCar der returnerer en Bil objekt. Dette kodeeksempel opfylder systemets funktionelle krav, men det forbinder for altid Betjent modsætter sig det med Bil. I denne situation siges det, at de to objekter er det tæt koblet. Det Betjent objekt kræver viden om Bil objekt og har adgang til alle offentlige metoder og variabler indeholdt i objektet. Det er bedst at undgå en så tæt kobling af kode, fordi den øger afhængigheden og reducerer fleksibiliteten.

For at kode Betjent objekt ved hjælp af grænseflader, kunne følgende implementering bruges:

klasse Betjent {public Vehicle getVehicle (Vehicle c) {...}} 

Mens kodeændringerne er ret små - ændrer referencerne fra Bil til Køretøj - virkningerne på udviklingscyklussen er betydelige. Brug af den anden implementering, Betjent har kun kendskab til de metoder og variabler, der er defineret i Køretøj interface. Alle andre offentlige metoder og data indeholdt i den specifikke implementering af programmet Køretøj interface er skjult for brugeren af Køretøj objekt.

Denne enkle kodeændring har sikret en korrekt skjuling af information og implementering fra andre objekter og har derfor elimineret muligheden for, at udviklere bruger uønskede metoder.

Oprettelse af interfaceobjektet

Det sidste emne, der skal diskuteres med hensyn til denne udviklingsteknik, er oprettelsen af ​​interfaceobjekterne. Mens det er muligt at oprette en ny forekomst af en klasse ved hjælp af ny operatør, er det ikke muligt direkte at oprette en forekomst af en grænseflade. For at oprette en interfaceimplementering skal du instantiere objektet og kaste det til den ønskede interface. Derfor kan udvikleren, der ejer objektkoden, være ansvarlig for både at oprette objektets forekomst og udføre castingen.

Denne oprettelsesproces kan opnås ved hjælp af en Fabrik mønster, hvor et eksternt objekt kalder et statisk createXYZ () metode på en Fabrik og returnerer en grænseflade. Det kan også opnås, hvis en udvikler kalder en metode på et andet objekt og sender det til et interface i stedet for den aktuelle klasse. Dette ville være analogt med at passere en Optælling interface i stedet for en Vektor eller Hashtable.

Detaljeret eksempel

For at demonstrere brugen af ​​denne ordning på et større projekt har jeg oprettet eksemplet med en mødeplanlægger. Denne planlægger har tre hovedkomponenter: ressourcerne (konferencelokale og mødedeltager), forekomsten (selve mødet) og planlæggeren (den, der vedligeholder ressourcekalenderen).

Lad os antage, at disse tre komponenter skulle udvikles af tre forskellige udviklere. Målet for hver udvikler skal være at etablere brugen af ​​hans eller hendes komponent og offentliggøre den til de andre udviklere på projektet.

Overvej eksemplet med en Person. EN Person kan implementere adskillige metoder, men vil implementere Ressource interface til denne applikation. Jeg har oprettet Ressource grænseflade med alle de nødvendige tilgangsmetoder til alle ressourcer, der bruges i dette eksempel (vist nedenfor):

offentlig grænseflade Ressource {public String getID (); offentlig String getName (); offentlig ugyldig tilføjelse Forekomst (forekomst o); } 

På dette tidspunkt, udvikleren af Person Funktionalitet har offentliggjort grænsefladen, hvormed alle brugere kan få adgang til de oplysninger, der er gemt i Person objekt. Kodning til grænsefladen hjælper med at sikre, at ingen udviklere bruger Person genstand på en forkert måde. Udvikleren af Planlægning objektet kan nu bruge metoderne i Ressource interface for at få adgang til de oplysninger og funktionalitet, der er nødvendige for at oprette og vedligeholde tidsplanen for Person objekt.

Det Hændelse interface indeholder metoder, der er nødvendige for planlægning af en Hændelse. Dette kan være en konference, rejseplan eller enhver anden planlægningshændelse. Det Hændelse interface er vist nedenfor:

offentlig grænseflade Forekomst {public void setEndDatetime (Date d); offentlig dato getEndDatetime (); public void setStartDatetime (Date d); offentlig dato getStartDatetime (); public void setDescription (strengbeskrivelse); offentlig streng getDescription (); offentlig ugyldig addResource (Ressource r); public Resource [] getResources (); offentlig boolsk forekommer På (Dato d); } 

Det Planlægning kode bruger Ressource interface og Hændelse interface til at opretholde tidsplanen for en ressource. Bemærk, at Planlægning ikke har noget kendskab til den enhed, som den opretholder tidsplanen for:

public class Scheduler implementerer Schedule {Vector schedule = null; offentlig planlægger () {tidsplan = ny vektor (); } public void addOccurrence (Forekomst o) {sched.addElement (o); } offentligt ugyldigt removeOccurrence (Forekomst o) {sched.removeElement (o); } public Occurrence getOccurrence (Date d) {Enumeration scheduleElements = schedule.elements (); Forekomst o = null; while (scheduleElements.hasMoreElements ()) {o = (Forekomst) planElements.nextElement (); // I dette enkle eksempel matcher forekomsten, hvis // datatiden er mødets starttid. Denne logik // kan gøres mere kompleks efter behov. hvis (o.getStartDatetime () == d) {pause; }} returner o; }} 

Dette eksempel viser styrken af ​​grænseflader i et systems udviklingsfaser. Hvert af delsystemerne har kun viden om grænsefladen, som det skal kommunikere igennem - der kræves ingen viden om implementeringen. Hvis hver af byggestenene i ovenstående eksempel skulle udvikles yderligere af team af udviklere, ville deres bestræbelser blive forenklet på grund af håndhævelsen af ​​disse interface-kontrakter.

Afsluttende tanker om grænseflader

Denne artikel har vist nogle af fordelene ved kodning til grænseflader. Denne teknik muliggør større effektivitet gennem hver fase af udviklingslivscyklussen.

I projektets designfaser giver grænseflader hurtig etablering af de ønskede interaktioner mellem objekter. Implementeringsobjekter tilknyttet en given grænseflade kan defineres, efter at metoderne og kravene til den grænseflade er specificeret. Jo hurtigere interaktionen etableres, jo hurtigere kan designfasen udvikle sig til udvikling.

Grænseflader giver udviklere mulighed for at eksponere og begrænse bestemte metoder og information til brugerne af deres objekter uden at ændre tilladelserne og den interne struktur for selve objektet. Brug af grænseflader kan hjælpe med at eliminere de irriterende fejl, der vises, når kode udviklet af flere udviklingsteam er integreret.

Kontrakthåndhævelse leveres af grænsefladen. Da grænsefladen generelt er aftalt i designfasen af ​​projektet, har udviklerne mulighed for at koncentrere sig om deres individuelle moduler uden at skulle bekymre sig om modulerne fra deres kolleger. Integrering af disse delsystemer gøres mere effektiv ved, at kontrakterne allerede er håndhævet i hele udviklingsfasen.

Til testformål kan der oprettes et simpelt driverobjekt til implementering af de aftalte grænseflader. Ved hjælp af dette objekt kan udviklere fortsætte deres arbejde med den viden, at de bruger de rigtige metoder til at få adgang til objektet. Når objekterne distribueres i et testmiljø, erstattes driverklasserne med de sande klasser, så objektet kan testes uden kode- eller egenskabsændringer.

Denne ordning giver mulighed for nem udvidelse af dette system; i vores eksempel kunne vi udvide koden til at omfatte flere former for ressourcer, såsom mødelokaler og lyd- / videoudstyr. Enhver yderligere implementering af programmet Ressource interface passer ind i den etablerede mekanisme uden at ændre den eksisterende kode. Store projekter, der bruger denne ordning, kunne designes og implementeres på en sådan måde, at yderligere funktionalitet kan tilføjes uden større ændringer i infrastrukturen. Som et eksempel er Konferencerum objekt blev oprettet. Dette objekt implementerer Ressource interface og kan interagere med Tidsplan og Hændelse implementatorer uden at ændre infrastrukturen.

En anden fordel er den centrale placering af koden. Hvis der skal tilføjes nye metoder til Ressource interface, vil alle implementeringer af denne grænseflade blive identificeret som kræver ændring. Dette reducerer den efterforskning, der kræves for at bestemme den mulige indvirkning af ændringer i grænsefladen.

Ud over fordelene ved udviklingen giver teknikken, der præsenteres i denne artikel, projektledelse forsikring om, at interobjekt- eller intersystemkommunikationsmønstre er etableret og håndhævet gennem hele udviklingscyklussen. Dette reducerer risikoen for fejl i projektets integrations- og testfaser.