Når man lærer seg objektorientert programmering, og etter å ha lært seg det grunnleggende om objekter, felt og metoder, bruker man mesteparten av tiden på arv. Arv betyr at vi overtar en del av implementasjonen fra en basisklasse. Du trenger bare å lage en underklasse av en basisklasse for å arve alle ikke-private felt og metoder.
En bil og et fly er kjøretøyer, så det er åpenbart at begge disse klassene bør utvides fra sin felles basisklasse Vehicle. Dette er et typisk akademisk eksempel, men når vi bestemmer oss for å binde disse klassene med arverelasjonen, bør vi være oppmerksomme på noen konsekvenser.
Fig. 1 Implementering av arverelasjon.
I dette tilfellet er klassene tett knyttet til hverandre - det betyr at endringer i oppførselen til hver klasse kan oppnås ved å gjøre endringer i baseklassen kode. Dette kan være både en fordel og en ulempe - det avhenger av hva slags oppførsel vi forventer. Hvis arven brukes på feil tidspunkt, kan prosessen med å legge til en ny funksjon støte på noen implementeringsvansker fordi den ikke passer inn i den opprettede klassemodellen. Vi må velge mellom å duplisere koden og å omorganisere modellen - og det kan være en tidkrevende prosess. Vi kan kalle koden som utfører arverelasjonen for "åpen-lukket" - det vil si at den er åpen for utvidelser, men lukket for endringer. Hvis vi antar at det i Vehicle-klassen finnes en generell, definert motordrift for hvert kjøretøy, må vi gjøre noen alvorlige endringer i klassene våre i det øyeblikket vi ønsker å legge til en modell for et motorløst kjøretøy (f.eks. en sykkel) i klassehierarkiet vårt.
klasse Kjøretøy
def start_motor
end
def stop_engine
end
end
class Plane < Kjøretøy
def move
start_motor
...
stop_engine
end
end
Sammensetning
Hvis vi bare er interessert i en del av oppførselen til den eksisterende klassen, er et godt alternativ til arv å bruke komposisjon. I stedet for å lage underklasser som arver alle egenskaper (de vi trenger og de vi ikke trenger i det hele tatt), kan vi isolere de funksjonene vi trenger, og utstyre objektene våre med referanser til dem. På en slik måte gir vi opp tanken om at objektet er en type et basisobjekt, til fordel for påstanden om at Den inneholder bare noen deler av egenskapene.
Fig. 2 Bruk av komposisjonen
På denne måten kan vi isolere koden som er ansvarlig for motordriften, til den autonome klassen Engine, og kun referere til den i de klassene som representerer kjøretøy med motor. Ved å isolere funksjonene ved hjelp av komposisjon blir kjøretøyklassestrukturen enklere, og innkapslingen av de enkelte klassene styrkes. Nå er den eneste måten kjøretøyene kan påvirke motoren på, å bruke det offentlige grensesnittet, fordi de ikke lenger vil ha informasjon om implementasjonen. I tillegg vil det være mulig å bruke forskjellige typer motorer i forskjellige kjøretøyer, og til og med tillate utveksling av dem mens programmet kjører. Selvfølgelig er det ikke feilfritt å bruke komposisjon - vi lager et løst koblet klassesett, som enkelt kan utvides og er åpent for modifikasjoner. Men samtidig er hver klasse koblet til mange andre klasser, og må ha informasjon om grensesnittene deres.
klasse Kjøretøy
ende
klasse Motor
def start
end
def stop
end
end
class Plane < Kjøretøy
def initialize
@engine = Engine.new
end
def move
@engine.start
@engine.stop
end
def change_engine(ny_motor)
@engine = ny_engine
end
end
Valget
Begge beskrevne tilnærminger har fordeler og ulemper, så hvordan velge mellom dem? Arv er en spesialisering, så det er best å bruke dem bare for problemer, der det er "is-a" -typerelasjoner - så vi håndterer det virkelige hierarkiet av typer. Fordi arv knytter klasser tett sammen, bør vi for det første alltid vurdere om vi skal bruke komposisjon eller ikke. Komposisjon bør brukes for problemer der det finnes "har-en"-typerelasjoner - så klassen har mange deler, men den er noe mer enn et sett med klasser. Et fly består av deler, men alene er det noe mer - det har flere evner, for eksempel å fly. Hvis vi går videre med dette eksemplet, kan enkeltdeler forekomme i forskjellige spesialiserte varianter, og da er det et godt tidspunkt å bruke arv.
Både arv og komposisjon er bare verktøy som programmererne har til rådighet, så det krever erfaring å velge riktig verktøy for et bestemt problem. Så la oss øve og lære av feilene våre 🙂 🙂 .