Visual Basic 2005 Coach



Dovnload 477.64 Kb.
Pagina8/13
Datum20.08.2016
Grootte477.64 Kb.
1   ...   5   6   7   8   9   10   11   12   13

7.2. Een aantal basisconcepten

Aangezien object-oriëntatie het paradigma vormt voor ontwikkeling in .NET, en dus ook in Visual Basic 2005, is het van levensbelang de basisconcepten goed onder de knie te krijgen. U zult namelijk niet enkel zelf dergelijke objecten bouwen maar ook dagelijks in contact komen met de Base Class Library (BCL) van .NET die in feite een ruime collectie van dergelijke objecten (en andere zaken, zie verder) is.



7.2.1. Objecten en klassen

In het centrum van object-oriëntatie staat – hoe raadt u het? – het concept van een object. In feite is een object een entiteit die “iets” voorstelt. Dit “iets” is zéér ruim en kan gaan van concrete zaken zoals een “Klant” of een “Product” tot objecten die puur te maken hebben met de werking van het platform of computer-gerelateerde zaken zoals bijvoorbeeld een encryptie-algoritme of een bestand. Hoe dan ook, een object is iets dat concreet voorstelbaar is. Beschouw even het voorbeeld van een “Auto” object dat we verder zullen gebruiken als basisvoorbeeld. In feite zijn alle auto’s qua definitie hetzelfde, het zijn objecten die kunnen voortbewegen en dus een bepaald gedrag vertonen. De definitie van het abstracte concept van een “Auto” is wat we een klasse noemen. Objecten zijn dan instanties van klassen. De klasse waarvan een object een instantie is, noemt met ook het type van dat object. In Visual Basic ziet dit er als volgt uit:


Dim mijnAuto As Auto

mijnAuto = New Auto


Dim autoVanMijnBuur As New Auto
In beide gevallen wordt een nieuwe instantie (sleutelwoord New) van het type “Auto” gemaakt en toegekend aan een variabele. Zoals u ook weet uit vorige versies van Visual Basic worden variabelen gedeclareerd met behulpt van het sleutelwoord Dim. Merk hierbij op dat elke gedeclareerde variabele een type heeft. Een object van een ander type kan dan nooit toegekend worden aan die variabele, een eigenschap die door de Common Language Runtime bewaakt wordt onder de noemer “type safety”. Dit wijkt dus af van de benadering bij oudere versies van Visual Basic waar het gebruik van sterk-getypeerde variabelen (door gebruik van een type Variant) niet noodzakelijk was. Indien u uit die wereld komt, kent u ongetwijfeld het befaamde Option Explicit waarmee u deze “flexibele modus” kon uitschakelen, wat ook vaak gezien werd als een “best practice”. In de wereld van .NET is sterke typering de standaard en enkel om redenen van backward compatibility kan daarvan afgeweken worden, maar hierover zullen we nu niet uitwijden.
Nu, wat maakt zoal de definitie uit van een klasse? Twee zaken, met name data en operaties. Elke instantie – een object dus – van een bepaalde klasse stelt een concrete “status” voor. Bij ons voorbeeld van auto’s kan je bijvoorbeeld de snelheid als een statuskenmerk zien dat variabel is in de tijd. Dit maakt dus deel uit van de data geassocieerd met het object. Daarnaast zijn er ook operaties die inwerken op deze status, direct of indirect. Zo zullen zaken zoals “versnellen”, “start”, “rem” tot de operaties van een auto-object behoren.

7.2.2. Leden van een klasse

Alles wat de definitie uitmaakt van een klasse noemen we de leden (“members”) van die klasse. Hieronder verstaan we dus enerzijds de data en anderzijds de operaties. Maar vooraleer we hierop ingaan, moeten we eerst de syntax zien voor het declareren van een klassedefinitie (dit is niet hetzelfde als het declaren van een variabele van het beschouwde type). Een voorbeeld:


Class Auto
'Leden van de klasse komen hier
End Class

7.2.2.1. Attributen

Vervolgens dienen we uiteraard de leden van de klasse te concretiseren. Laten we beginnen met de data die wordt gedefinieerd aan de hand van “attributen”. Een voorbeeldje ziet er als volgt uit:


Class Auto
Private snelheid As Double
End Class
Bovenstaande definitie betekent dat met elke variabele van het type Auto een (verborgen) variabele is geassocieerd die de snelheid van de auto voorstelt. Uiteraard kan je extra attributen toevoegen, maar het principe blijft hetzelfde. De reden waarom deze variabele privaat gedeclareerd is, noemt men encapsulatie en komt neer op het verbergen van de interne status om direct toegang te vermijden. Immers, vaak zal validatie van invoer nodig zijn en is het niet gezond de interne status van een object rechtstreeks te veranderen. Het veranderen van de status dient dan ook te gebeuren via operaties.
Noot: Het begrip “attributen” wordt in .NET ook in een andere (meer geavanceerde) context gebruikt als benaming voor een totaal ander concept. We zullen hierop later ingaan.

7.2.2.2. Methoden

Dergelijke operaties noemt men methoden. Een voorbeeld:


Class Auto
Private snelheid As Double
Public Sub Versnel()

If snelheid < 140 Then

snelheid = snelheid + 1

End If


End Sub
Public Sub Vertraag()

If snelheid > 0 Then

snelheid = snelheid - 1

End If


End Sub
End Class
Noot: Over de discrete voorstelling van een continu verschijnsel zoals versnelling en remkracht doen we hier evenwel geen uitspraak.
In ons geval noemen we deze methoden ook wel procedures vermits ze geen waarde teruggeven. Een methode die data teruggeeft noemt men een functie, zoals volgend voorbeeld aangeeft:
Public Function MargeTotMaximumSnelheid() As Double

Return 140 - snelheid

End Function

Verder kunnen procedures en functies ook parameters hebben, zoals hieronder geïllustreerd:


Public Sub Versnel(ByVal acceleratie As Double)

Dim resultaat As Double = snelheid * acceleratie


If resultaat < 140 Then

snelheid = resultaat

End If

End Sub
Merk ook op dat binnen de definie van een klasse meerdere methoden kunnen gedeclareerd worden met dezelde naam maar een verschillende signatuur. Onder signatuur verstaan we het type dat teruggegeven wordt (bij functies) alsook de diverse parameters en hun types die worden meegegeven aan de methode (bij een functie of procedure). Het declareren van verschillende methodes met eenzelfde naam noemen we “overloading”. Volgende definitie van onze Auto-klasse is dan ook perfect geldig:


Class Auto
Private snelheid As Double
Public Sub Versnel()

If snelheid < 140 Then

snelheid = snelheid + 1

End If


End Sub
Public Sub Versnel(ByVal acceleratie As Double)

Dim resultaat As Double = snelheid * acceleratie


If resultaat < 140 Then

snelheid = resultaat

End If

End Sub
Public Sub Vertraag()



If snelheid > 0 Then

snelheid = snelheid - 1

End If

End Sub
Public Function MargeTotMaximumSnelheid() As Double



Return 140 - snelheid

End Function


End Class
Verder heeft elke methode – net zoals elk ander lid van een klassedefinitie overigens – een “visibiliteitskenmerk” dat aangeeft waar gebruik ervan mogelijk is. In ons geval hebben we alle methoden als Public gedeclareerd, hoewel andere “modifiers” ook mogelijk zijn. Zo zal men help-methodes die enkel intern noodzakelijk zijn typisch als Private declareren. Andere mogelijkheden zijn Protected, Friend en Protected Friend. Bij de Protected modifier zijn de aangeduide leden enkel toegankelijk vanuit subklassen, iets wat we verder aanhalen. De Friend modifier beperkt zichtbaarheid tot de assembly waartoe de member behoort en zal veelal gebruikt worden om “helperklassen” binnen een assembly te markeren. Merk op dat al deze “modifiers” bruikbaar zijn op diverse elementen, waaronder klassen, methoden, interfaces, etc.

7.2.2.3. Properties

Een derde element dat typisch mede de dienst uitmaakt van een klassedefinitie zijn de properties. Kort gesteld vormen deze gemakkelijke toegang tot de achterliggende (private) attributen van een klasse. In wezen zijn properties niks meer dan een eenvoudige vorm om een zogenaamde getter en/of setter te definiëren. Een voorbeeldje zal veel verduidelijken:


Class Auto
Private snelheid As Double
Public Property Snelheid As Double

Get


Return snelheid

End Get


Set(ByVal value As Double)
snelheid = value

End Set


End Property
End Class
Uiteraard is het ook mogelijk extra logica toe te voegen aan een getter of een setter, zoals het controleren van invoer op geldigheid (bijvoorbeeld indien een waarde zich tussen een minimum en een maximum moet bevinden). In ons geval zou de property “Snelheid” overigens beter enkel een getter bevatten, vermits het dient als “verklikker” van de status van onze Auto-instantie:

Class Auto


Private snelheid As Double
Public ReadOnly Property Snelheid As Double

Get


Return snelheid

End Get
End Property


End Class
Een gebruiker van deze klasse, bijvoorbeeld het dashboard van de auto, kan dan gebruik maken van deze klasse op een manier zoals de volgende:
Dim auto As New Auto()

Do While auto.Snelheid < 120

auto.Versnel()

Loop
Voor de geïnteresseerden raad ik aan een kijkje te nemen in de IL-code van onze klassedefinitie om u ervan te vergewissen dat een property effectief omgezet wordt in een getter- en/of setter-methode met prefixes get_ en set_.



7.2.2.4. Constructoren

Naast de “klassieke” methoden (inclusief properties) zijn er ook speciale methoden die impliciet worden aangeroepen in bepaalde stadia van de levenscyclus van een instantie van een klasse. De meest klassieke zijn de zogenaamde constructoren. In vorige codefragment werd reeds een constructor opgeroepen, met name op de regel:


Dim auto As New Auto()
In werkelijkheid wordt hier de methode New() uit de klasse Auto opgeroepen. De “default constructor” (dit is een constructor zonder parameters) wordt automatisch aangemaakt indien deze niet door de programmeur werd gespecifieerd. We zouden evenwel onze eigen logica kunnen schrijven om de instantie (intern) te initialiseren:
Class Auto
Public Sub New()

End Sub
End Class


In deze methode kan u alle initialisatielogica plaatsen die u maar wenst, bijvoorbeeld om de initiële waarden van attributen in te stellen of instanties van helperklassen aan te maken. Naast parameterloze constructoren kunt u vanzelfsprekend ook constructoren definiëren die parameters accepteren, bijvoorbeeld de initiële waarden voor de diverse attributen.


7.2.2.5. Events

Alle voorgaande members die we tot nu toe besproken hebben, vereisen invocatie aan de kant van de gebruiker van de klasse. Zo zal men via het sleutelwoord New de constructor oproepen en via de . operator interageren met methodes en properties. Met andere woorden, de gebruiker (consumer) van de klasse neemt het initiatief. Events werken in de andere richting en laten een object toe statuswijzigingen te rapporteren aan de gebruikers ervan. Als gebuikers abbonneert (subscribe) u zich op dergelijke events.


Een klassiek voorbeeld zijn UI controls (zoals knoppen) op een Windows Forms formulier die events hebben zoals Click, welke opgeroepen worden indien de gebruiker op de control (knop) klikt.
Werken met events bestaat dus uit 2 delen. Enerzijds het event definiëren op klasseniveau en anderzijds het gebruik ervan waar nodig. Laten we beide zaken nader onder de loep nemen en beginnen met het declareren van een event in onze Auto-klasse:
Class Auto
Public Event SnelheidsWijziging(ByVal snelheid As Double)
End Class
Vervolgens dient u uiteraard het event op te roepen op elke plaats waar u (geïnteresseerde) gebruikers van de klasse wenst op de hoogte te brengen van een statusverandering. In dit geval zult u dit doen in de methoden Versnel en Vertaag, zoals hieronder weergegeven:
Class Auto
Private snelheid As Double
Public Event SnelheidsWijziging(ByVal snelheid As Double)
Public Sub Versnel()

If snelheid < 140 Then

snelheid = snelheid + 1

RaiseEvent SnelheidsWijziging(snelheid)

End If

End Sub
Public Sub Versnel(ByVal acceleratie As Double)



Dim resultaat As Double = snelheid * acceleratie
If resultaat < 140 Then

snelheid = resultaat

RaiseEvent SnelheidsWijziging(snelheid)

End If


End Sub
Public Sub Vertraag()

If snelheid > 0 Then

snelheid = snelheid - 1

RaiseEvent SnelheidsWijziging(snelheid)

End If

End Sub
End Class


Via het sleutelwoord RaiseEvent roept u het event op (raise) en zal de uitvoeringsomgeving automatisch alle abbonnees op de hoogte brengen van de wijziging. Laten we dus nu een kijkje nemen aan de andere kant van het verhaal, het consumeren (consume) van events. Hiervoor bestaan diverse mogelijkheden, waaronder de volgende:
Class Dashboard
Private auto As Auto
Public Sub New(ByRef auto As Auto)

Me.auto = auto

AddHandler auto.SnelheidsWijziging, AddressOf WijzigSnelheid

End Sub
Private Sub WijzigSnelheid(ByVal snelheid As Double)

'Wijzig de snelheidsindicator op het dashboard

End Sub
End Class

Via het sleutelwoord AddHandler wordt de interesse in een bepaald event aangegeven door een event te verbinden met een event handler. De eerste parameter van AddHandler is het event waarin we geïnteresseerd zijn, in dit geval het SnelheidsWijziging event van ons auto-object. De tweede parameter verwijst naar de lokale methode die de afhandeling van het event zal uitvoeren en wordt gerefereerd via AddressOf.
Een alternatief is gebruik te maken van de sleutelwoorden WithEvents en Handles, zoals hieronder aangegeven:
Class Dashboard
Private WithEvents auto As Auto
Public Sub New(ByRef auto As Auto)

Me.auto = auto

End Sub
Private Sub WijzigSnelheid(ByVal snelheid As Double) _

Handles auto.SnelheidsWijziging

'Wijzig de snelheidsindicator op het dashboard

End Sub
End Class


Elke keer de snelheid van de auto gewijzigd wordt zal het dashboard nu op de hoogte gebracht worden.

7.2.2.6. Gedeelde members

Tot nu toe hebben we klassemembers besproken die verbonden zijn met de instantie van een object. Telkens we een nieuwe instantie van Auto creëren, zal bijvoorbeeld een geassocieerde snelheid worden geïnitialiseerd en gebruikt die specifiek is voor die Auto-instantie. In sommige gevallen is het echter ook handig members te hebben die gedeeld worden door alle instanties van de klasse, de zogenaamde gedeelde (of ook wel statische) members. Een klassiek voorbeeld is een instantieteller die bijhoudt hoeveel instanties van een bepaalde klasse ooit gemaakt zijn:


Class Auto
Private Shared instantieTeller As Integer
Public Sub New()

instantieTeller = instantieTeller + 1

End Sub
Public Shared ReadOnly Property Instanties() As Integer

Get


Return instantieTeller

End Get


End Property
End Class
Diverse members kunnen als Shared gedeclareerd worden, waaronder attributen en methoden.

7.2.3. Overzicht

In volgende figuur ziet u een overzicht van een typische klasse, grafisch in beeld gebracht:


De klasse Balloon bevat 3 properties, namelijk Color, Height en Diameter. Daarnaast is er methode Puncture() en zijn er 2 events, met name Deflate en MakeNoise. De gebruiker van een ballon kan nieuwe instanties aanmaken, de diverse properties instellen, zich abbonneren op de diverse events (bijvoorbeeld om een geluid af te spelen als de ballon ontploft) en uiteraard methodes oproepen.



7.2.4. Modules versus klassen

Een belangrijk onderscheid is dat tussen modules en klassen. Het essentiële verschil komt erop neer dat een module standaard gedeeld wordt en er maar één instantie van is, terwijl klassen echte OO-objecten vormen waarvan meerdere instanties gemaakt kunnen worden en waarbij members desgewenst als Shared kunnen gedeclareerd worden. Alle leden van een module zijn daarentegen impliciet gedeclareerd als Shared. Voor meer informatie over dit onderscheid verwijzen we door naar de MSDN documentatie.



7.2.5. Interfaces

Een ander belangrijk concept uit de wereld vna object-oriëntatie is het concept van een interface. De beste manier om over interfaces na te denken is als een contract. In ons voorbeeld van een auto vormt de stuurinrichting van de auto een interface naar de gebruiker toe. Ongeacht het type auto gekocht wordt, de basisfuncties zullen steeds hetzelfde gedrag vertonen. Zo zal een draai aan het stuur naar rechts ervoor zorgen dat de auto naar rechts opdraait en zal een trap op de rem zorgen dat de auto tot stilstand komt. Hoe dit alles intern geïmplementeerd is (mechanisch, via computersturing), hoeft de gebruiker niet te weten zolang de implementatie maar aan het contract voldoet. Een (beperkt) voorbeeldje:


Interface IAuto
Function BerekenAantalResterendeKilometers() As Double

Sub Stuur(ByVal hoek As Double)

Sub Start()

ReadOnly Property Snelheid() As Double


End Interface
Noot: Bij afspraak worden interfaces in .NET aangeduid met een hoofdletter I aan het begin. Dit is louter conventioneel maar het wordt aangeraden deze conventie te volgen.
U kan ongetwijfeld nog veel meer members voor deze interface bedenken. Bij het definiëren van een interface dient u wel zorgzaam te zijn om enkel deze members op te nemen die voor alle implementaties van de interface van toepassing zijn. Zo zal cruise-control functionaliteit voor een algemene interface van een auto niet gewenst zijn, vermits niet alle modellen dergelijke ondersteuning (dienen te) bieden.
Een volgende stap is het implementeren van de interface via het sleutelwoord Implements wat er als volgt uitziet:
Class KlassiekeAuto

Implements IAuto


'Andere attributen voor onderdelen enz.
Private bezinePeil As Double

Private snelheid As Double


'Constructoren toevoegen
Public Function BerekenAantalResterendeKilometers() As Double

Return bezinePeil

End Function
Public Sub Stuur(ByVal hoek As Double)

'Implementeer stuurfunctionaliteit via achterliggende onderdelen

End sub
Public Sub Start()

'Start de motor enz.

End sub
Public ReadOnly Property Snelheid() As Double

Get


Return snelheid

End Get


End Property
End Class
Een implementatie moet alle members uit de interfacedefinitie implementeren, zoniet spreken we van een abstracte klasse (zie verder). Stel nu dat u een gebruiker van elke mogelijke auto wenst te definiëren, bijvoorbeeld in de context van een taxibedrijf met een carpool. De representatie van een taxi-taak ziet er dan als volgt uit:
Class TaxiJob
Private bestuurder As Bestuurder

Private auto As IAuto


Public Sub New(ByRef bestuurder As Bestuurder, ByRef auto As IAuto)

Me.auto = auto

Me.bestuurder = bestuurder

End Sub
Public Sub GaNaarEnHaalOp(ByRef gps As GpsCoordinaat)

auto.Start()

'Voer taak verder uit

End Function
End Class
Zoals u ziet in bovenstaand codevoorbeeld, werkt een TaxiJob samen met om het even welk type auto door gebruik te maken van de interface IAuto. Komt er morgen een nieuwe soort auto’s in de carpool van het taxibedrijf dan zullen alle TaxiJobs gewoon kunnen uitgevoerd worden, zolang deze auto’s aan hetzelfde contract voldoen.

7.2.6. Abstracte klassen

Abstracte klassen houden het midden tussen klassen en interfaces in die zin dat een reeks members ongespecifieerd zijn, terwijl andere geïmplementeerd zijn. In ons voorbeeld met auto’s kan je de basismodellen van een auto-productiereeks zien als abstracte klassen. Het is bijvoorbeeld perfect mogelijk een basismodel te assembleren waarin reeds een groot deel van de implementatie bepaald is, zoals bijvoorbeeld de stuurinrichting, de verlichting, de zetels, enz maar waarin nog de implementatie voor de motor ontbreekt. Deze auto zal niet rijden en is dus een abstracte klasse. Het implementeren van extra functionaliteit zal vereist zijn om een bruikbare wagen te verkrijgen.


In het kader van deze Visual Basic 2005 Coach zullen we niet verder ingaan op het concept van abstracte klassen maar vanzelfsprekend is meer informatie terug te vinden in de MSDN documentatie.



1   ...   5   6   7   8   9   10   11   12   13


De database wordt beschermd door het auteursrecht ©opleid.info 2017
stuur bericht

    Hoofdpagina