|
Dit artikel is gepubliceerd op zondag 31 juli 2011 op vbvoorbeelden, bezoek de website voor een recente versie van dit artikel of andere artikels.
9.10.1. Waarvoor is Inheritance BruikbaarHet kan voorkomen dat je nieuwe klasse die je wenst te definiëren zou willen baseren op een andere klasse. Waarbij je dus stelt dat hetgeen dat gedefinieerd is in die andere klasse zou willen herbruiken in je nieuwe klasse. Hier komt overerving ( ook wel inheritance genoemd ) van pas. Inheritance zorgt ervoor dat de afgeleide klasse ( derived/child class ) alle members overneemt van de basisklasse ( base/parent class ).
Hieronder zie je een voorbeeld van inheritance. Visual Basic 2010 Broncode Class Person Private m_Name As String Public Property Name() As String Get Name = m_Name End Get Set( ByVal value As String) m_Name = value End Set End PropertyEnd ClassClass Student : Inherits Person Private m_ClassGroup As String Public Property ClassGroup() As String Get ClassGroup = m_ClassGroup End Get Set( ByVal value As String) m_ClassGroup = ClassGroup End Set End PropertyEnd ClassDownload Visual Basic 2010 Broncode Download Visual C# Sourcecode
De Student klasse erft hier over van de Person klasse, en neemt daarbij ook alle members over die gedefinieerd zijn in die basisklasse. In onderstaande client kun je merken dat men op een object van het type Student nu ook de ( overgeërfde ) property Name kunt gebruiken. Naast Name kan natuurlijk bijvoorbeeld ook ClassGroup worden gebruikt die in de klasse Student zelf werd gedefinieerd. Visual Basic 2010 Broncode Module Client1 Sub Main() Dim person1 As Person = New Person person1.Name = "John" Console.WriteLine(person1.Name) Dim student1 As Student = New Student student1.Name = "Jane" Console.WriteLine(student1.Name) student1.ClassGroup = "Group 1" Console.WriteLine(student1.ClassGroup) Console.ReadLine() End SubEnd ModuleDownload Visual Basic 2010 Broncode Download Visual C# Sourcecode
Console Application Output John
Jane
Group 1 boven
9.10.2. Hoe Inheritance GebruikenInheritance wordt toepast door in de afgeleide klasse een Inherits clausule op te nemen, ofwel op dezelfde regel als de identifier van de afgeleide klasse ( met een : voor de Inherits clausule ), ofwel met de Inherits clausule op de eerste regel van de klassedefinitie van de afgeleide klasse. Visual Basic 2010 Broncode Class Teacher Inherits Person Private m_Course As String Public Property Course() As String Get Course = m_Course End Get Set( ByVal value As String) m_Course = value End Set End PropertyEnd ClassDownload Visual Basic 2010 Broncode Download Visual C# Sourcecode
boven
9.10.3. Single InheritanceZoals je hierboven merkt kan men van één basisklasse meerdere afgeleide klassen definiëren. Men kan in Visual Basic echter wel slechts van één klasse overerven ( "single inheritance" ), in tegenstelling tot bepaalde andere OOPs waar men van meerdere klassen kan overerven ( "multiple inheritance" ). boven
9.10.4. Single en Static ClassificationEen object is in Visual Basic altijd een instantie van één bepaalde klasse ( "single classification" ), dat type van object kan ook nooit wijzigen ( "static classification" ), in tegenstelling tot sommige OOPs waar men een object kan maken van meerdere klassen ( "multiple classification" ) of een object van type/klasse kan laten veranderen ( "dynamic classification" ). boven
9.10.5. Wanneer Inheritance ToepassenWanneer inheritance van toepassing is tussen twee klassen, is er doorgaans een "is een" relatie tussen objecten van die twee entiteiten. In dit voorbeeld kan je stellen een Student of een Teacher is een Person. Verwar dit niet met de "heeft een" relatie die bij containment van toepassing is. Enkele voorbeelden waarbij inheritance van toepassing zou kunnen zijn : een woonhuis is een gebouw, een wagen is een voertuig, een bediende is een werknemer, een tekstverwerker is een programma, ... . Let echt op dat men gespecialiseerde ( afgeleide ) types niet verward met instanties, bijvoorbeeld John is een persoon. Hierbij is John eerder een instanties, en niet zozeer een subtype.
Een afgeleide klasse kan ook een basisklasse vormen voor andere afgeleide klassen. Eigenlijk dient gesteld te worden dat iedere klasse die je zelf definieert een afgeleide klasse is. Voeg je zelf niet expliciet een Inherits clausule toe aan een klasse, dan staat er eigenlijk by default Inherits System.Object. De klasse Person bijvoorbeeld is dus een afgeleide van het type System.Object. Later wordt meer uitleg gegeven over dit overkoepelend basistype ( System.Object ).
Inheritance zowel als containment zijn twee technieken om herbruik van code te verwezenlijken. Bij containment kan je de members van het gerefereerde object aanspreken en dus herbruiken, bij inheritance worden de members gewoon overgeërfd, waardoor ze ook herbruikbaar zijn op of voor dat object van de afgeleide klasse.
Misbruik echter inheritance niet om simpelweg in uw afgeleide klasse de members niet te hoeven herdefiniëren die zijn overgeërfd. De kracht van inheritance is immers niet zo zeer herbruik van code, maar eerder "dynamisch polymorfisme" waarbij objecten een andere gespecialiseerde vorm kunnen aannemen ( later meer over polymorfisme ).
Goede richtlijnen die je als vereiste kan hanteren voor het gebruik van inheritance zijn : - de "is een" regel - de "100 procent" regel : 100 procent van de members ( of dus alle members ) die gedefinieerd zijn in de basisklasse moeten ook bruikbaar zijn in de afgeleide klasse Het valt aan te raden pas inheritance toe te passen indien aan beide regels voldaan is.
Anders gesteld zijn er twee invalshoeken om tot inheritance te komen : - generalisatie : hier merk je dat verschillende klassen gemeenschappelijke members hebben, waarbij je dus de beslissing zou kunnen maken een basistype te definiëren waarin het gemeenschappelijke wordt gedefinieerd, ander typen die dan ook deze gemeenschappelijke members nodig hebben, kunnen dan ook van die basisklasse overerven - specialisatie : hier bemerk je eerder dan een nieuw type dat je dient te definiëren eigenlijk een specialisatie is van een reeds bestaand type, waardoor je besluit van dat bestaand type over te erven en daaraan de gespecialiseerde kenmerken gaat toevoegen Het resultaat is bij generalisatie of specialisatie hetzelfde, namelijk overerving, het zijn louter verschillende uitgangspunten van waaruit je kan vertrekken om tot inheritance te komen.
Onthoud voorlopig ook nog dat eens een member met een bepaalde signatuur is overgenomen uit een basisklasse, je niet zomaar in de afgeleide klasse een member kan toevoegen met dezelfde signatuur. Later gaan we hier verder op in. boven
9.10.6. Een Ander VoorbeeldWe gaan in onderstaand voorbeeld uit van een klasse Counter, waarbij men op objecten van dit type de Value ( tellerwaarde ) kan opvragen ( via de GetValue() method ). En waarbij de mogelijkheid bestaat via members in de publieke interface van dit type de Value te verhogen ( Raise() method ) of te verlagen ( Lower() method ). Visual Basic 2010 Broncode Class Counter Protected m_Value As Integer Public Function GetValue() As Integer GetValue = m_Value End Function Public Sub Raise() m_Value += 1 End Sub Public Sub Lower() m_Value -= 1 End SubEnd ClassDownload Visual Basic 2010 Broncode Download Visual C# Sourcecode
Naderhand wensen we een gespecialiseerd type van Counter te creëren, namelijk een specialisatie waar het ook mogelijk wordt de Value in te stellen.
We beslissen hiervoor een afgeleide klasse SettableCounter te creëren en er een SetValue(...) method aan toe te voegen.
Allerhande redenen kunnen ervoor zorgen dat je Counter niet wil of kan wijzigen. Het zou simpelweg kunnen voorvallen dat je niet wil riskeren om de bestaande klasse corrupt te maken. Het zou ook kunnen dat je de abstractie van de klasse niet wil aanpassen, een waarde-instelbare en waarde-niet-instelbare teller is immers niet hetzelfde. Het zou ook kunnen de je de basisklasse niet kan aanpassen omdat je niet over de broncode beschikt, en enkel over de gecompileerde klasse beschikt. Visual Basic 2010 Broncode Class SettableCounter : Inherits Counter Public Sub SetValue( ByVal value As Integer) m_Value = value End SubEnd ClassModule Client2 Sub Main() Dim counter1 As Counter = New Counter With counter1 Console.WriteLine(.GetValue() = 0) .Raise() Console.WriteLine(.GetValue() = 1) .Lower() Console.WriteLine(.GetValue() = 0) End With Dim specialCounter1 As SettableCounter = New SettableCounter With specialCounter1 Console.WriteLine(.GetValue() = 0) .SetValue(10) Console.WriteLine(.GetValue() = 10) .Raise() Console.WriteLine(.GetValue() = 11) .Lower() Console.WriteLine(.GetValue() = 10) End With Console.ReadLine() End SubEnd ModuleDownload Visual Basic 2010 Broncode Download Visual C# Sourcecode
Console Application Output True
True
True
True
True
True
True boven
9.10.7. Access Modifier ProtectedZoals we reeds wisten zijn Private members enkel beschikbaar binnen de klasse zelf en zijn Public members overal ( inclusief voor de client ) bereikbaar. Deze keywords geven aan of wijzigen dus het toegangs-/accessbereik van die members, vandaar de term "accessmodifiers". Protected members zijn best vergelijkbaar met Private members, alleen zijn ze niet louter binnen de klasse ( waarin ze zijn gedefinieerd ) beschikbaar, maar zijn ze ook toegankelijk voor de afgeleide klasse. Clients echter hebben geen toegang tot deze members.
Het veld m_Value gedefinieerd in de basisklasse Counter mag ingekapseld worden ( dus niet Public ) omdat het niet toegankelijk moet zijn voor de clients van Counter. Afgeleide klassen van Counter zouden echter wel nut kunnen hebben aan toegang tot het veld m_Value. Zo geeft SettableCounter het veld m_Value nodig om in de SetValue method de Value toestand te kunnen wijzigen. Daarom kan hier aan het veld m_Value hier een Protected access modifier worden gegeven.
Men zou dus steeds bij het opnemen van ingekapselde members ( niet publieke members ) moeten nagaan of afgeleiden nut kunnen hebben aan toegang tot deze member. Hebben de afgeleiden geen nut aan toegang tot die member dan kan die member als Private worden gedefinieerd, is er wel nut voor de afgeleiden aan toegang tot die member dan kan deze member als Protected worden gedefinieerd.
Voor alle duidelijkheid dus nog eens stellen : Public members die zijn overgeërfd zijn ook beschikbaar voor client op objecten van dat afgeleid type. Vergis je echter niet : niet alleen Public en Protected members worden overgeërfd, ook de Private members worden overgenomen, alleen zijn die niet toegankelijk, zelfs niet voor afgeleide klassen. Het gebruik van Private en Protected members is dus een vorm van encapsulation ( inkapseling ) waarvan het gebruik van die members voor de client ( Protected ) en eventueel ook voor de afgeleide klasse zelf ( Private ) verhinderd wordt. boven
9.10.8. OefeningenOpgave 1 :
Maak de nodige klassen om voorstellingen van personeelsleden te kunnen maken. Een personeelslid heeft als eigenschappen : een naam en een adres ( een adres houdt in een straat, een huisnummer, een postcode en een gemeente ).
Zorg er ook voor dat we voorstellingen kunnen maken van managers. Managers zijn personeelsleden met meer verantwoordelijkheden en hebben als eigenschappen : een naam, een adres en een wagen ( van een bepaald merk ). Oplossing 1 : Visual Basic 2010 Broncode Class Address Private m_Street As String Public Property Street() As String Get Street = m_Street End Get Set( ByVal value As String) m_Street = value End Set End Property Private m_Number As String Public Property Number() As String Get Number = m_Number End Get Set( ByVal value As String) m_Number = value End Set End Property Private m_ZipCode As String Public Property ZipCode() As String Get ZipCode = m_ZipCode End Get Set( ByVal value As String) m_ZipCode = value End Set End Property Private m_City As String Public Property City() As String Get City = m_City End Get Set( ByVal value As String) m_City = value End Set End PropertyEnd ClassClass Employee Private m_Name As String Public Property Name() As String Get Name = m_Name End Get Set( ByVal value As String) m_Name = value End Set End Property Private m_Address As Address Public Property Address() As Address Get Address = m_Address End Get Set( ByVal value As Address) m_Address = value End Set End PropertyEnd ClassClass Manager : Inherits Employee Private m_Car As Car Public Property Car() As Car Get Car = m_Car End Get Set( ByVal value As Car) m_Car = value End Set End PropertyEnd ClassClass Car Private m_Brand As String Public Property Brand() As String Get Brand = m_Brand End Get Set( ByVal value As String) m_Brand = value End Set End PropertyEnd ClassDownload Visual Basic 2010 Broncode Download Visual C# Sourcecode
Opgave 2 : Hieronder worden een aantal zelfstandige naamwoorden of eigennamen vermeld :
Sarkozy, monarch, Paris, country, United Kingdom, president, monarchy, France, capital, London, Elizabeth, republic
Gebruik zelf alle bovenvermelde woorden in uw oplossing. Kies zelf of het woord best past als klasse-identifier, member-identifier, toestandswaarde of object-identifier.
Pas inheritance toe, daar waar je denkt dat het nuttig is. Oplossing 2 : Visual Basic 2010 Broncode Module Exercise2Solution Sub Main() Dim france As Republic = New Republic france.Capital = "Paris" france.President = "Sarkozy" Dim unitedKingdom As Monarchy = New Monarchy unitedKingdom.Capital = "London" unitedKingdom.Monarch = "Elizabeth" End SubEnd ModuleClass Country Private m_Capital As String Public Property Capital() As String Get Capital = m_Capital End Get Set( ByVal value As String) m_Capital = value End Set End PropertyEnd ClassClass Monarchy : Inherits Country Private m_Monarch As String Public Property Monarch() As String Get Monarch = m_Monarch End Get Set( ByVal value As String) m_Monarch = value End Set End PropertyEnd ClassClass Republic : Inherits Country Private m_President As String Public Property President() As String Get President = m_President End Get Set( ByVal value As String) m_President = value End Set End PropertyEnd ClassDownload Visual Basic 2010 Broncode Download Visual C# Sourcecode
Dit artikel is gepubliceerd op zondag 31 juli 2011 op vbvoorbeelden, bezoek de website voor een recente versie van dit artikel of andere artikels.
|