Java interfaces frem for abstrakte klasser

Tags:    java interface abstrakt

Jeg er lidt i tvivl omkring hvornår det er godt at benytter interfaces frem for abstrakte klasser i java..
Jeg kan se en pointe med at vælge en abstract class frem for interface fordi at en subclass til en abstract class kun skal implementere de abstrakte metoder og ikke de "normale".. En interface kræver at man implementerer ALLE dens metoder.

Hvorfor laver man ikke bare lave en abstract class KUN med abstrakte metoder i? Ville det ikke være det samme ?? .. Det går jeg selvfølgelig ikke ud fra, da der må være en mening med at bruge interfaces



Indlæg senest redigeret d. 21.06.2013 12:43 af Bruger #15621
5 svar postet i denne tråd vises herunder
2 indlæg har modtaget i alt 13 karma
Sorter efter stemmer Sorter efter dato
Prøver lige at forklare det på en anden måde:


Der er ingen fordele så at sige for de dækker over to forskellige ting. Vil dog meget hellere mangle abstrakte klasser end interfaces.

Vi skal lave et program der kan fortælle tiden baseret på ure. Vi tænker at en ur har to visere, en til timer og en til minutter. Så der er noget fællestræk vi kan smide i en abstrakt klasse i stedet. Alt underklasserne skal gøre er at fortælle os hvor viserne er:

Fold kodeboks ind/udJava kode 


Succes. Vi har sparet alle fremtidige implementører af urer besværet med at skulle omregne til tid. De kan nu nemt lave deres eget:

Fold kodeboks ind/udJava kode 


På samme måde kan Rolex lave deres. Siden de alle arver fra Watch har de jo også getTime. Vores system kender kun til superklassen Watch. Så vores system ved kun der er nogen Watch'es, og den kan kalde getTime på dem. Men hov, hvad nu hvis vi har brug for et digital ur? Vores system kender kun til Watch så vi er tvunget til at bruge en halvfærdig implementation der arbejder med visere, i stedet for 'segmenter' som et digital ur bruger. Men det kan vi stadig gøre ved lidt grimt kodning:

Fold kodeboks ind/udJava kode 

Det bliv da noget værre rod. Vi skulle implementere viserne siden vi ikke kan have abstrakte metoder i en ikke-abstrakt klasse. I stedet for at de 2 metoder gjor det simplere skulle vi nu udover dem også selv implementere getTime. Vi har ikke vundet noget ved arve fra Watch hvilket er et krav. I stedet er vi blevet straffet med to overflødige metoder vi ikke havde brug for. Problemet her er at da vi lavede vores abstrakte klasse antog vi visse fællestræk som alle vores underklasser vil have. Som så mange andre steder i udviklingsverdenen viste det sig at være forkert. Alle der ikke skulle implementere et analog ur bliver straffet. Dette inkluderer implementation af et AtomUr som kunden også vil have understøttet i morgen.

Nåh hvad kan vi gøre ved det. Igen læg mærke til at pointen med Interfaces og Abstrakte klasser er vidt forskellige i dette afsnit. Hvad er det egenligt et ur skal kunne? Det skal blot kunne fortælle tiden. Men det er heller ikke forkert at alle analog ure, og alle digitale urer har visse fællestræk som vi kan tage fordel af. Det er bare ikke ALLE ure som deler disse fællestræk. Lad os bruge vores nylig fundne viden til at refaktore koden:

Alt et ur skal kunne er at fortælle tiden. Lad os lave et interface til det:

Fold kodeboks ind/udJava kode 


I stedet for at bruge den abstrakte klasse Watch (den tidligere), bruger vi nu interfacet Watch. Hvad ved vi om analoge urer? De kan fortælle tiden og har visere. Lads os ændre vores gamle watch til at repræsentere dette:

Fold kodeboks ind/udJava kode 


Ligeledes med digitale ure. Vi behøver ikke længere arve fra AnalogWatch og blive straffet for det. Vi implementerer bare Watch direkte:

Fold kodeboks ind/udJava kode 


Et digitalt ur kunne nedarve fra den og behøvede blot at fortælle hvilke segmenter der er oplyste. De behøver ikke implementere getTime igen. Bemærk her at abstrakte klasser gør det mere bekvemmeligt at implementere nye ure, mens det er interfaces der gør det mulige at have andre ure på. Vi kan sagten implementere nye ure uden at gøre brug af abstrakt og de vil virke i vores system siden det kun gør brug af objekter af typen Watch:

Fold kodeboks ind/udJava kode 


Håber det forklarede det bedre.

(Sidenote: Den måde abstrakte klasser bliver brugt på her, er et eksempel på mønsteret Template method pattern.)



Indlæg senest redigeret d. 21.06.2013 14:39 af Bruger #14645
Der er flere fordele ved interfaces. Den første regel for objektorienteret programmering siger: "kod ALTID mod en abstraktion ALDRIG mod en implementation". Det vil sige at du altid koder mod interfaces.

Lav fx et interface der abstraherer din database forbindelse:

Fold kodeboks ind/udJava kode 


Koden overfor beskriver hvordan dit database lag ser ud. Du kan nu kode resten af din applikation og blot bruge interfacet i stedet for en klasse. Det behøver ikke engang at være implementeret for at du kan kode videre. Det du nu kan er at lave forskellige klasser der implementerer dit interface. fx. en til mysql, en til mssql, en til oracle og en til xml filer. Det ændret ikke på dit program, det er jo abstraheret via et interface.

Der hvor det bliver smart er at du kan lave en dummy implementation af din database, således kan du nemt "simulere" og unit teste. Det vil sige du laver en klasse som implementerer dit interface, men ikke gør noget. Så kan du nu teste dit program uden at være forbundet til en database.



Må indrømme jeg ser ikke fordelen ved en abstract klasse i dit første afsnit. Hvorfor er:

Fold kodeboks ind/udJava kode 


Bedre end:
Fold kodeboks ind/udJava kode 


En klasse kan godt have andre metoder end det interfacen siger.

I et interface er du stadig fri til at arve fra en anden klasse.

En abstrakt klasse kan du ikke instantiere, men den kan have logik (kode) og det kan et interface ikke.

Hvis du ved hvordan alle underklasser vil implementere noget specielt og der er meget overlap så kan det være en god ide at bruge en abstrakt klasse, for så slipper underklasserne for at implementere det hele igen. Hvis der ikke er det (den typisk situation, efter min mening) vil et interface være bedre.

Men du kan faktisk få fordelene ved begge to, ved at lade din abstrakte klasse implementere dit interface. Dvs. du har begge:
Fold kodeboks ind/udJava kode 


På den her måde får du begge fordelene. Lad os sige at du gerne vil lave en klasse som implementerer MyAwesomeInterface. Så kan du arve MyAwesomeDoingClass (den abstrakte) hvis den gør noget af det du ellers selv ville skulle gøre. Dvs. du slipper for at implementere SetAwesomeThing, og skal kun implementere DoAwesomeThing. Hvis den abstrakte klasse derimod ikke gør tingene på din måde, eller du gerne vil arve fra en anden klasse, har du stadig interfacet så du kan lave det fra bunden. Dette er selvfølgelig et kunstigt eksempel.

Med interfacet har du stadig fordelene nævnt i den forrige tråd. Hvis du i stedet bruge den abstrakte klasse i gennem din kode er alle tvungne til at arve fra den klasse. Men på denne her måde har de både mulighed for at arve fra din klasse, eller selv implementere interfacet.

Faktisk kan get være en meget dårlig idé at lave en klasse abstrakt i stedet for et interface (uden at den implementer det aktuelle interface). Et eksempel er Observer mønsteret i Java hvilket er temmelig dårlig lavet for at sige det lige ud: http://stackoverflow.com/questions/7281469/why-is-java-util-observable-not-an-abstract-class






Indlæg senest redigeret d. 21.06.2013 13:11 af Bruger #14645
Nåå ja det kan et interface jo også .. ja er ny til interfaces og har stadig ikke fat i hvorfor de er smarte at bruge.

Hvis du ved hvordan alle underklasser vil implementere noget specielt og der er meget overlap så kan det være en god ide at bruge en abstrakt klasse, for så slipper underklasserne for at implementere det hele igen. Hvis der ikke er det (den typisk situation, efter min mening) vil et interface være bedre.

Hvorfor ville et interface være bedre i det tilfælde?


Edit:
jeg spørger lige på en anden måde:
Hvad er fordelene ved at bruge abstrakte klasser frem for interfaces?
Og omvendt?



Indlæg senest redigeret d. 21.06.2013 13:45 af Bruger #15621
Har lidt bedre forståelse for det nu, men bliver nok nødt til at rodde mere med det selv før jeg har det hele på plads

tak for forklaringen :)



Indlæg senest redigeret d. 21.06.2013 15:39 af Bruger #15621
t