Programmering

Smartere Java-utvikling

En rask og enkel ordning for å øke utviklingen av store Java-applikasjoner innebærer bruk av grensesnitt. Java-grensesnitt er en plan for funksjonaliteten i et tilknyttet objekt.

Ved å integrere grensesnitt i ditt neste prosjekt, vil du merke fordeler gjennom hele livssyklusen til utviklingsarbeidet ditt. Teknikken med å kode til grensesnitt i stedet for objekter vil forbedre effektiviteten til utviklingsteamet ved å:

  • Tillater utviklingsteamet å raskt etablere samspillet mellom de nødvendige objektene, uten å tvinge den tidlige definisjonen av støtteobjektene
  • Gjør det mulig for utviklere å konsentrere seg om utviklingsoppgavene sine med kunnskapen om at integrering allerede er tatt i betraktning
  • Tilbyr fleksibilitet slik at nye implementeringer av grensesnittene kan legges til det eksisterende systemet uten større kodendringer
  • Håndheve kontraktene som er blitt avtalt av medlemmer av utviklingsteamet for å sikre at alle objekter samhandler som designet

Et overblikk

Fordi objektorientert utviklingsarbeid involverer samspill mellom objekter, er det viktig å utvikle og håndheve sterke kontrakter mellom disse objektene. Teknikken med å kode til grensesnitt innebærer bruk av grensesnitt, i stedet for objekter, som den primære kommunikasjonsmetoden.

Denne artikkelen vil introdusere brukeren til begrepet koding til grensesnitt gjennom et enkelt eksempel. Et detaljert eksempel følger, som hjelper til med å demonstrere verdien av denne ordningen i et større system som krever flere utviklere. Før vi kommer til eksempelkoden, la oss imidlertid se på fordelene med koding til grensesnitt.

Hvorfor kode til grensesnitt?

Java-grensesnittet er en utviklingskontrakt. Det sikrer at et bestemt objekt tilfredsstiller et gitt sett med metoder. Grensesnitt brukes i hele Java API for å spesifisere den nødvendige funksjonaliteten for objektinteraksjon. Eksempler på bruk av grensesnitt er tilbakekallingsmekanismer (Eventlyttere), mønstre (Observatør), og spesifikasjoner (Kjørbar, Serialiserbar).

Koding til grensesnitt er en teknikk der utviklere kan eksponere visse metoder for et objekt for andre objekter i systemet. Utviklerne som mottar implementeringer av disse grensesnittene, har muligheten til å kode til grensesnittet i stedet for koding til selve objektet. Med andre ord ville utviklerne skrive kode som ikke interagerte direkte med et objekt som sådan, men heller med implementeringen av objektets grensesnitt.

En annen grunn til å kode til grensesnitt i stedet for til objekter er at det gir høyere effektivitet i de forskjellige fasene av et systems livssyklus:

  • Design: metodene til et objekt kan raskt spesifiseres og publiseres for alle berørte utviklere
  • Utvikling: Java-kompilatoren garanterer at alle metodene i grensesnittet implementeres med riktig signatur og at alle endringer i grensesnittet umiddelbart er synlige for andre utviklere
  • Integrering: det er muligheten for raskt å koble klasser eller delsystemer sammen på grunn av deres veletablerte grensesnitt
  • Testing: grensesnitt hjelper til med å isolere feil fordi de begrenser omfanget av en mulig logisk feil til et gitt delsett av metoder

Det er noe overhead forbundet med denne utviklingsteknikken på grunn av den nødvendige kodeinfrastrukturen. Denne infrastrukturen inkluderer både grensesnitt for interaksjonen mellom objekter og påkallingskode for å lage implementeringer av grensesnitt. Denne overhead er ubetydelig sammenlignet med den enkle og fordelen ved å bruke grensesnitt som beskrevet.

Grunnleggende eksempel

For å forklare begrepet koding til grensesnitt ytterligere, har jeg laget et enkelt eksempel. Selv om dette eksemplet helt klart er trivielt, viser det noen av fordelene nevnt ovenfor.

Tenk på det enkle eksemplet på en klasse Bil som implementerer grensesnitt Kjøretøy. Grensesnitt Kjøretøy har en enkelt metode kalt start(). Klasse Bil vil implementere grensesnittet ved å tilby en start() metode. Annen funksjonalitet i Bil klassen har blitt utelatt for klarhets skyld.

grensesnitt Kjøretøy {// Alle kjøretøyimplementeringer må implementere startmetoden offentlig ugyldig start (); } klasse bilimplementerer kjøretøy {// Nødvendig for å implementere kjøretøyets ugyldige start () {...}} 

Etter å ha lagt grunnlaget for Bil objekt, kan vi lage et annet objekt som heter Betjent. Det er den Betjentsin jobb å starte Bil og ta det med til restaurantens skytshelgen. De Betjent objektet kan skrives uten grensesnitt, som følger:

class Betjent {public Car getCar (Car c) {...}} 

De Betjent objektet har en metode som kalles getCar som returnerer a Bil gjenstand. Dette kodeeksemplet tilfredsstiller systemets funksjonelle krav, men det forbinder alltid Betjent objekt med den fra Bil. I denne situasjonen sies det at de to objektene er det sammensveiset. De Betjent objektet krever kunnskap om Bil objekt og har tilgang til alle offentlige metoder og variabler som finnes i objektet. Det er best å unngå en så tett kobling av kode fordi den øker avhengigheten og reduserer fleksibiliteten.

For å kode Betjent objekt som bruker grensesnitt, kan følgende implementering brukes:

class Valet {public Vehicle getVehicle (Vehicle c) {...}} 

Mens kodeendringene er ganske små - endrer referansene fra Bil til Kjøretøy - effektene på utviklingssyklusen er betydelige. Ved hjelp av den andre implementeringen, Betjent har kun kunnskap om metodene og variablene som er definert i Kjøretøy grensesnitt. Alle andre offentlige metoder og data som finnes i den spesifikke implementeringen av Kjøretøy er skjult for brukeren av Kjøretøy gjenstand.

Denne enkle kodeendringen har sikret riktig skjult informasjon og implementering fra andre objekter, og har derfor eliminert muligheten for at utviklere vil bruke uønskede metoder.

Opprette grensesnittobjektet

Den siste utgaven å diskutere med hensyn til denne utviklingsteknikken er etableringen av grensesnittobjektene. Selv om det er mulig å opprette en ny forekomst av en klasse ved hjelp av ny operatør, er det ikke mulig å opprette en forekomst av et grensesnitt direkte. For å lage en grensesnittimplementering, må du instantiere objektet og kaste det til ønsket grensesnitt. Derfor kan utvikleren som eier objektkoden være ansvarlig for både å lage forekomsten av objektet og utføre castingen.

Denne opprettelsesprosessen kan oppnås ved hjelp av a Fabrikk mønster der et eksternt objekt kaller et statisk createXYZ () metode på en Fabrikk og returnerer et grensesnitt. Det kan også oppnås hvis en utvikler kaller en metode på et annet objekt og sender det til et grensesnitt i stedet for den faktiske klassen. Dette ville være analogt med bestått en Oppregning grensesnitt i stedet for en Vector eller Hashtable.

Detaljert eksempel

For å demonstrere bruken av denne ordningen på et større prosjekt, har jeg laget eksemplet på en møteplanlegger. Denne planleggeren har tre hovedkomponenter: ressursene (konferanserom og møtedeltaker), forekomsten (selve møtet) og planleggeren (den som vedlikeholder ressurskalenderen).

La oss anta at disse tre komponentene skulle utvikles av tre forskjellige utviklere. Målet til hver utvikler bør være å etablere bruken av komponenten og publisere den til de andre utviklerne på prosjektet.

Tenk på eksemplet med a Person. EN Person kan implementere mange metoder, men vil implementere Ressurs grensesnitt for dette programmet. Jeg har opprettet Ressurs grensesnitt med alle nødvendige tilgangsmetoder for alle ressurser som brukes i dette eksemplet (vist nedenfor):

offentlig grensesnitt Ressurs {public String getID (); offentlig String getName (); public void addOkkurrence (Occurrence o); } 

På dette punktet, utvikleren av Person funksjonalitet har publisert grensesnittet der alle brukere kan få tilgang til informasjonen som er lagret i Person gjenstand. Koding til grensesnittet bidrar til å sikre at ingen utviklere bruker Person objekt på en feil måte. Utvikleren av Planlegger objektet kan nå bruke metodene i Ressurs grensesnitt for å få tilgang til informasjon og funksjonalitet som er nødvendig for å lage og vedlikeholde tidsplanen for Person gjenstand.

De Hendelse grensesnitt inneholder metoder som er nødvendige for planlegging av et Hendelse. Dette kan være en konferanse, reiseplan eller andre planleggingshendelser. De Hendelse grensesnittet er vist nedenfor:

offentlig grensesnitt 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 (Ressurs r); public Resource [] getResources (); offentlig boolsk forekommer På (Dato d); } 

De Planlegger koden bruker Ressurs grensesnitt og Hendelse grensesnitt for å opprettholde tidsplanen for en ressurs. Legg merke til at Planlegger har ingen kjennskap til enheten som den holder tidsplanen for:

public class Scheduler implementerer Schedule {Vector schedule = null; offentlig planlegger () {tidsplan = ny vektor (); } public void addOccurrence (Occurrence o) {sched.addElement (o); } offentlig tomrom removeOccurrence (Forekomst o) {sched.removeElement (o); } public Occurrence getOccurrence (Date d) {Enumeration scheduleElements = sched.elements (); Forekomst o = null; while (scheduleElements.hasMoreElements ()) {o = (Forekomst) planElements.nextElement (); // For dette enkle eksemplet samsvarer forekomsten med // datatiden er møtet starttid. Denne logikken // kan gjøres mer kompleks etter behov. hvis (o.getStartDatetime () == d) {pause; }} returner o; }} 

Dette eksemplet viser kraften til grensesnitt i utviklingsfasene til et system. Hvert av delsystemene har kun kunnskap om grensesnittet det skal kommunisere gjennom - ingen kunnskap om implementeringen er nødvendig. Hvis hver av byggesteinene i eksemplet ovenfor skulle utvikles videre av team av utviklere, ville deres innsats bli forenklet på grunn av håndhevelsen av disse grensesnittkontraktene.

Avsluttende tanker om grensesnitt

Denne artikkelen har vist noen av fordelene med koding til grensesnitt. Denne teknikken muliggjør større effektivitet gjennom hver fase av utviklingslivssyklusen.

I prosjektets designfaser tillater grensesnitt rask etablering av ønsket interaksjon mellom objekter. Implementeringsobjektene tilknyttet et gitt grensesnitt kan defineres etter at metodene og kravene til det grensesnittet er spesifisert. Jo raskere interaksjonen blir etablert, desto raskere kan designfasen utvikle seg til utvikling.

Grensesnitt gir utviklere muligheten til å eksponere og begrense visse metoder og informasjon til brukerne av objektene sine uten å endre tillatelsene og den interne strukturen til selve objektet. Bruk av grensesnitt kan bidra til å eliminere de irriterende feilene som vises når kode utviklet av flere utviklingsteam er integrert.

Kontrakthåndhevelse er gitt av grensesnittet. Fordi det generelt er enighet om grensesnittet under prosjekteringsfasen av prosjektet, har utviklerne muligheten til å konsentrere seg om sine individuelle moduler uten å måtte bekymre seg for modulene til sine kolleger. Integrering av disse delsystemene effektiviseres av at kontraktene allerede er håndhevet gjennom hele utviklingsfasen.

For testformål kan det opprettes et enkelt driverobjekt for å implementere de avtalte grensesnittene. Ved å bruke dette objektet kan utviklere fortsette arbeidet med kunnskapen om at de bruker de riktige metodene for å få tilgang til objektet. Når objektene distribueres i et testmiljø, erstattes driverklassene med de sanne klassene, slik at objektet kan testes uten endringer i kode eller eiendom.

Denne ordningen gir mulighet for enkel utvidelse av dette systemet; i vårt eksempel kan vi utvide koden til å omfatte flere former for ressurser, for eksempel møterom og lyd- / videoutstyr. Eventuell ytterligere implementering av Ressurs grensesnittet passer inn i den etablerte mekanismen uten å endre den eksisterende koden. Store prosjekter som bruker denne ordningen, kan utformes og implementeres på en slik måte at tilleggsfunksjonalitet kan legges til uten større endringer i infrastrukturen. Som et eksempel, den Konferanserom objekt ble opprettet. Dette objektet implementerer Ressurs grensesnitt og kan samhandle med Rute og Hendelse implementatorer uten å endre infrastrukturen.

En annen fordel er den sentraliserte plasseringen av koden. Hvis nye metoder skal legges til i Ressurs grensesnitt, vil alle implementeringer av dette grensesnittet bli identifisert som krever endring. Dette vil redusere etterforskningen som kreves for å bestemme den mulige effekten av endringer i grensesnittet.

I tillegg til fordelene med utviklingen, gir teknikken som presenteres i denne artikkelen prosjektledelse forsikring om at interobjekt- eller intersystemkommunikasjonsmønstre er etablert og håndhevet gjennom hele utviklingssyklusen. Dette reduserer risikoen for feil under integrasjons- og testfasen av prosjektet.

$config[zx-auto] not found$config[zx-overlay] not found