Eclipse-plattform
API-regler som gjelder
Versjon 0.15 - Sist endret 12.00, 30. mai 2001
Her er reglene som gjelder for klienter av APIen for Eclipse-plattformen (og andre komponenter).
Hva det betyr å være API
Eclipse-plattformen definerer API-elementer som skal brukes av klientene, det vil si ISVer som skriver til
plugin-moduler. Disse plugin-modulene kan så definere API-elementer for klientene, og så videre. API-elementer er
det ansiktet utad: de inneholder en spesifikasjon om hva det er meningen at de skal gjøre, og om
hvordan det
er meningen at de skal brukes. API-elementer støttes: Eclipse-plattformgruppen vil rette implementeringsfeil der det
er avvik fra den spesifiserte virkemåten. Siden det ofte er kostnadskrevende med store API-endringer, vil
Eclipse-plattformgruppen også prøve å utvikle API-elementer gradvis gjennom suksessive hovedutgaver.
Hvordan skille API fra ikke-API
API-elementer er av natur dokumentert og har en spesifikasjon, i motsetning til ikke-API-elementer som er
interne implementeringer som vanligvis ikke har publisert dokumentasjon eller spesifikasjoner. Så hvis det er noe
du ikke finner dokumentasjon om, er det vanligvis en god indikasjon på at det ikke er en API.
For å prøve å gjøre forskjellen tydeligere er kodegrunnlaget delt inn i API-pakker og ikke-API-pakker, der alle
API-elementene er oppgitt i definerte API-pakker.
-
API-pakke - en Java-pakke som inneholder minst en API-klasse eller ett API-grensesnitt. Navn på API-pakker
er oppgitt i dokumentasjonen for komponenten, og der det er mulig, vil alle andre pakker som bare inneholder
implementeringsdetaljer, ha "internal" i pakkenavnet. Navnene på API-pakker kan blir vist i klientkoden. For
Eclipse-plattformen gjelder det følgende:
-
org.eclipse.foo.* - for eksempel org.eclipse.swt.widgets,
org.eclipse.ui eller
org.eclipse.core.runtime
-
org.eclipse.foo.internal.* - ikke API, interne implementeringspakker
-
org.eclipse.foo.examples.* - ikke API, dette er eksempler
-
org.eclipse.foo.tests.* - ikke API, dette er testpakker
-
API-klasse eller API-grensesnitt - en public-klasse eller et grensesnitt i en API-pakke, eller en
public- eller protected-klasse eller et grensesnittmedlem oppgitt i, eller arvet av, en annen
API-klasse eller et annet grensesnitt.
Navnene på API-klasser og API-grensesnitt kan blir vist i klientkoden.
-
API-metode eller konstruktør - en public- eller protected-metode eller konstruktør som
enten er oppgitt i, eller arvet av, en API-klasse eller et API-grensesnitt. Navnene på API-metoder kan blir vist i
klientkoden.
-
API-felt - et public- eller protected-felt som enten er oppgitt i, eller arvet fra, en
API-klasse eller et grensesnitt. Navnene på API-felt kan blir vist i klientkoden.
Alt annet blir betraktet som interne implementeringsdetaljer og er forbudt område for alle klienter. Tillatt
klientkode må aldri referere til navn på ikke-API-elementer (selv ikke med Java-refleksjon). I noen tilfeller blir
Java-språkets tilgjengelighetsregler for navn brukt for å hindre ugyldige referanser.
Det er imidlertid mange
tilfeller der dette ganske enkelt ikke er mulig. Hvis du følger denne ene enkle regelen, unngår du
problemet fullstendig:
-
Hold deg til offisielt dokumenterte APIer. Referer bare til pakker som er dokumentert i published API
Javadoc for komponenten.
Referer aldri til en pakke som hører til en annen komponent som har "internal"
i navnet - de er aldri API. Referer aldri til en pakke som det ikke er publisert API Javadoc for - de er heller
ikke API.
Generelle regler
Spesifikasjonene av API-elementer blir generert fra Javadoc-kommentarer i elementets Java-kildekode. For noen
typer elementer er spesifikasjonen i form av en kontrakt. Når det for eksempel gjelder metoder, er kontrakten
mellom to parter, den som kaller opp metoden, og den som implementerer metoden. Den grunnleggende regelen er:
-
Overhold alle kontrakter. Kontraktene er beskrevet i den publiserte Javadoc for API-elementene du bruker.
Termen "må" (must), når den er brukt i en API-kontrakt, betyr at parten plikter å sikre at betingelsen alltid blir
oppfylt. Hvis parten unnlater å gjøre det, blir det betraktet som en programmeringsfeil med uspesifiserte (og
kanskje uventede) konsekvenser.
-
Du må overholde "må" (must). Vær spesielt oppmerksom på betingelser der "må" (must) er brukt.
Andre fornuftige regler:
-
Ikke stol på tilfeldig virkemåte. Tilfeldig virkemåte er virkemåte som er observert ved
eksperimentering eller i praksis, men som ikke er garantert av noen API-spesifikasjon.
-
Ikke betrakt null som et objekt. Null er heller mangelen på et objekt.
Anta at alt er forskjellig fra
null hvis ikke API-spesifikasjonen sier noe annet.
-
Ikke prøv å jukse med Java-refleksjon. Det hjelper ikke å bruker Java-refleksjon for å omgå
kontroll av Java-kompilatoren. Det er ingen ekstra API-kontrakter som gjelder for refleksjon. Refleksjon øker
bare sannsynligheten for at du stoler på uspesifisert virkemåte og interne implementeringsdetaljer.
-
Bruk dine egne pakker. Ikke deklarer kode i en pakke som tilhører en annen komponent. Du skal alltid
deklarere din egen kode i dine egne pakker.
Kalle opp felles API-metoder
For de fleste klienter vil størstedelen av Eclipse-APIen være i form av fellesmetoder i API-grensesnitt eller
klasser, slik at klienten kan kalle dem opp ved behov.
-
Kontroller forhåndsbetingelsene. Pass på at en API-metodes forhåndsbetingelser er oppfylt før du
kaller opp metoden. Kalleren
kan da trygt anta at metodens etterbetingelser blir oppfylt umiddelbart etter retur fra kallet.
-
Null-parametere. Ikke send null som en parameter til en API-metode hvis det ikke eksplisitt er
dokumentert at parameteren tillater null. Dette er kanskje den vanligste programmeringsfeilen.
-
Begrensede kallere. Ikke kall opp en API-metode som det er dokumentert at bare er tilgjengelig for bestemte
kallere, hvis ikke du er en av dem. I noen situasjoner må metoder være del av felles-APIen til nytte for en bestemt
klasse med kallere (ofte interne). Hvis du kaller opp en av disse metodene på feil tidspunkt, har det
uspesifiserte (og kanskje uventede) konsekvenser.
-
Feilsøkingsmetoder. Ikke kall opp en API-metode merket "for debugging
purposes only". For eksempel er de fleste toString()-metodene i denne kategorien.
-
Parameterregistrering. Ikke send en matrise, samling eller et annen objekt som kan endres, som en
parameter til en API-metode, for så å endre objektet. Dette vil skape problemer.
Opprette forekomster av plattform-API-klasser
Det er ikke meningen at hvem som helst skal kunne opprette forekomster av alle konkrete API-klasser.
API-klasser
har en kontrakt om opprettelse av forekomster som viser betingelsene for opprettelse av forekomster. Kontrakten
kan også dekke ting som residual initialiseringsansvar (for eksempel konfigurering av en bestemt egenskap før
forekomsten er fullstendig aktiv) og tilknyttet livssyklusansvar (for eksempel å kalle opp dispose() for
å frigjøre OS-ressurser som forekomsten opptar). Klasser som er utformet slik at klienter kan opprette forekomster
av dem, er eksplisitt flagget i Javadoc-klassekommentaren (med ord som "Clients
may instantiate.").
-
Begrensning i hvem som kan opprette forekomster. Ikke opprett en forekomst av en API-klasse som det er
dokumentert at bare er tilgjengelig for bestemte parter, hvis ikke du er en av dem.
I noen situasjoner må klasser
være del av felles-APIen til nytte for en bestemt part (ofte intern). Hvis du oppretter en forekomst av en av disse
klassene på feil måte, har det uspesifiserte (og kanskje uventede) konsekvenser.
Definere subklasser for plattform-API-klasser
Det er bare et delsett av API-klassene som ble utformet med tanke på å definere subklasser. API-klasser har en
subklassekontrakt som viser betingelsene for definering av subklasser. Denne kontrakten dekker
også initialiseringsansvar og livssyklusansvar. Klasser som er utformet slik at klienter kan definere
subklasser for dem, er eksplisitt flagget i Javadoc-klassekommentaren (med ord som "Clients may
subclass.").
-
Begrensning i hvem som kan definere subklasser. Ikke definer subklasser for en API-klasse som det ikke er
meningen at det skal defineres subklasser for. Se på disse klassene som om de er deklarert som endelige. (Disse
kalles noen ganger "soft final"-klasser).
Kalle opp beskyttede API-metoder
Det er vanligvis tillat å kalle opp arvede beskyttede metoder og fellesmetoder fra en subklasse. Du må imidlertid
ofte være mer forsiktig når du gjør det, enn når du kaller opp fellesmetoder fra utenfor hierarkiet.
Overstyre API-metoder
Det er bare et delsett av felles og beskyttede API-metoder som ble utformet med tanke på å bli overstyrt. Hver
API-metode har en subklassekontrakt som viser betingelsene for at en subklasse kan overstyre den. Som standard er
overstyring ikke tillat.
Det er viktig å kontrollere subklassekontrakten for metodeimplementeringen som faktisk
blir overstyrt. Betingelsene i subklassekontrakter blir ikke sendt automatisk når metoden blir overskrevet.
-
Ikke overstyr en felles eller beskyttet API-metode hvis det ikke eksplisitt er tillatt. Hvis ikke annet
er oppgitt, skal du behandle alle metoder som om de er deklarert som endelige. (Disse kalles noen ganger "soft
final"-metoder).
Hvis typen tillatt overstyring er
- "implement" - må abstraktmetoden som er deklarert for subklassen, implementeres av en konkret subklasse
- "extend" - må metoden som er deklarert for subklassen, starte metoden på superklassen (nøyaktig en gang)
- "re-implement" - må ikke metoden som er deklarert for subklassen, starte metoden på superklassen
- "override" - kan metoden som er deklarert for subklassen, fritt starte metoden på superklassen hvis det
er behov for det
-
Kontroller etterbetingelser. Pass på at eventuelle etterbetingelser som er oppgitt for API-metoden, oppfylles
av implementeringen når den returneres.
-
Kontroller forhåndsbetingelsene proaktivt. Ikke anta at forhåndsbetingelsene som er oppgitt for
API-metoden, nødvendigvis er oppfylt. Selv om det ikke kreves at metodeimplementering kontrollerer de oppgitte
forhåndsbetingelsene, er det vanligvis lurt å kontrollere dem (når det er mulig og relativt lite
kostnadskrevende), slik at kallere som ikke oppfører seg som de skal, blir avslørt.
-
Nullresultat. Ikke returner null som et resultat fra en API-metode hvis det ikke er eksplisitt
dokumentert (i grensesnittet eller subklassen) at resultatet tillater null.
-
Returner kopier. Ikke returner en uerstattelig matrise, samling eller et annet objekt som kan
endres, som resultatet av en API-metode. Returner alltid en kopi for å unngå problemer med kallere som kanskje
endrer objektet.
Implementere plattform-API-grensesnitt
Det er bare et delsett av API-grensesnitt som ble utformet med tanke på å bli implementert av klienter. API-grensesnitt
har en kontrakt som viser betingelsene for å implementere dem. Grensesnitt som er utformet slik at klienter
kan implementere dem, er eksplisitt flagget i Javadoc-klassekommentaren (med ord som "Clients may implement."). En
klient kan deklarere et delgrensesnitt for et API-grensesnitt hvis, og bare hvis, det er tillatt at klienter
implementerer det.
-
Begrensede implementerere. Ikke implementer et API-grensesnitt som det er dokumentert at bare
er tilgjengelig for bestemte parter, hvis ikke du er en av dem. I mange situasjoner blir grensesnitt brukt
til å skjule interne implementeringsdetaljer.
Implementere felles API-metoder
Se "Overstyre API-metoder".
Få tilgang til felt i API-klasser og grensesnitt
Klienter kan lese API-felt, og de fleste er endelige. Enkelte strukturliknende objekter har kanskje fellesfelt
som ikke er endelige, og disse kan klientene lese og skrive til, hvis ikke annet er oppgitt.
-
Nullfelt. Ikke sett et API-felt til null hvis det ikke er eksplisitt tillatt.
Omdanne objekter av en kjent API-type
Et objekt av en kjent API-type kan bare omdannes til en annen API-type (eller betinget omdannes med instanceof)
hvis dette er eksplisitt tillatt i APIen.
-
Cast og instanceof. Ikke bruk instanceof- og cast-uttrykk for å øke hva som er kjent om et objekt ut over
det som APIen støtter.
Feil bruk viser tilfeldige implementeringsdetaljer som ikke garanteres av APIen.
Og det er selvfølgelig alltid uheldig å omdanne et objekt til en ikke-API-klasse eller et grensesnitt.
Hvis reglene ikke følges
Enten det gjøres bevisst eller uforvarende får det konsekvenser hvis reglene ikke overholdes. Det ville kanskje
vært enklere for alle parter hvis det var et API-politi som arresterte deg hvis du brøt reglene. Slik er det
imidlertid ikke.
API-samsvar fungerer stort sett som et system som ikke kontrolleres, der hver klient har
ansvar for å kjenne til reglene og følge dem.
Kontraktene for API-elementene setter grenser for virkemåten som støttes og opprettholdes. Etter som
Eclipse-plattformen modnes og utvikles, er det API-kontraktene som styrer hvordan denne utviklingen skjer. Utenfor
disse kontraktene støttes ingenting, og alt kan endres uten forvarsel og når som helst (selv mellom utgaver eller
mellom forskjellige OS-plattformer). Klientkode som bryter reglene over, mislykkes kanskje på forskjellige
versjoner og rettelsesnivåer av plattformen, når de kjøres på forskjellige underliggende operativsystemer, når de
kjøres med en annen blanding av plugin-moduler som ligger i minnet, når de kjøres med et annet
arbeidsbenkperspektiv, og så videre. Det er ingen som er spesielt interessert i å spekulere på nøyaktig hvilke
konsekvenser et bestemt regelbrudd kan få. Til de av dere som velger å ignorere reglene, kan dere ikke komme og si at
dere ikke ble advart. Og ikke forvent stort mer enn en et medfølende "Hva var det jeg sa".
På den annen side, plugin-kode fra klienter som følger reglene over, skal fortsette å virke på forskjellige
versjoner og rettelsesnivåer av plattformen, på forskjellige underliggende operativsystemer, og skal kunne
eksistere sammen med andre plugin-moduler uten problemer. Hvis alle følger spillereglene, gir Eclipse-plattformen
en stabil og støttet basis som det kan bygges spennende nye produkter på.