|
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.4.1. ReadOnly PropertyRegelmatig zal het voorkomen dat property enkel uitleesbaar moet zijn, en dus niet instelbaar. Typische voorbeelden hiervoor zijn berekende en afleidbare eigenschappen. Als men bijvoorbeeld voor een Product de Price en het TaxPercentage kent, kan men hieruit ook de PriceIncludingTax bepalen.
Dergelijke abstracties kunnen we bekomen door gebruik te maken van een ReadOnly Property, deze heeft geen setter, maar bepaald enkel in zijn getter welke waarde wordt opgeleverd.
Hieronder een voorbeeld : Visual Basic 2010 Broncode Namespace ReadOnlyPropertyExample Class Product Private m_Price As Decimal Public Property Price() As Decimal Get Price = m_Price End Get Set( ByVal value As Decimal) m_Price = value End Set End Property Private m_TaxPercentage As Decimal Public Property TaxPercentage() As Decimal Get TaxPercentage = m_TaxPercentage End Get Set( ByVal value As Decimal) m_TaxPercentage = value End Set End Property Public ReadOnly Property PriceIncludingTax() As Decimal Get PriceIncludingTax = Price * (1 + (TaxPercentage / 100)) End Get End Property End Class Module Client Sub Main() Dim product1 As Product = New Product product1.Price = 100 product1.TaxPercentage = 8 Console.WriteLine(product1.PriceIncludingTax) Console.ReadLine() End Sub End ModuleEnd NamespaceDownload Visual Basic 2010 Broncode Download Visual C# Sourcecode
Console Application Output 108 In bovenstaande Client kan dus geen waarde worden toegekend aan de Property PriceIncludingTax.
De mogelijkheid bestaat uiteraard om ook die eigenschap writeable te maken, de keuze hangt vooral af van wat je in de client als input wil gebruiken : Price en Tax als input en PriceIncludingTax als afgeleide waarde of Price en PriceIncludingTax als input en Tax als afgeleide waarde of Tax en PriceIncludingTax als input en Price als afgeleide waarde Alle bovenstaande variaties zijn mogelijk, maar de eerst-vermeld lijkt misschien wel de meest logische. Men zou er ook voor kunnen opteren alle 3 de eigenschappen writeable te maken, maar dan bekom je een vreemde situatie. Als bijvoorbeeld de PriceIncludingTax wordt ingesteld moet je dan op basis hiervan en op basis van de Tax de Price afleiden, of moet je op basis hiervan en op basis van de Price de Tax afleiden. Je ziet het wordt verwarrend. Eender welke keuze je uiteindelijk ook zou maken, steeds zal je ervoor moeten zorgen dat de client-auteur hiervan op de hoogte kan zijn ( door dit aspect bijvoorbeeld in de klassedocumentatie te verduidelijken ). Maar hoe dan ook dergelijke verwarrende situatie is beter te vermijden. Het opstellen van een goede abstractie is continue zoeken naar een delicaat evenwicht, net voldoende mogelijkheden bieden aan de client van die klasse zonder verwarring te creëren is de kunst.
Merk ook op dat in bovenstaand voorbeeld in de implementatie van de Property PriceIncludingTax er gebruik wordt gemaakt van de ( publiek toegankelijke ) properties Price en TaxPercentage, en dus niet van de - in de klasse zelf ook toegankelijke - velden m_Price en m_TaxPercentage. Dit is doorgaans de beste keuze omdat je zeker kunt stellen dat de publieke members ( die je dus ook aan de clients aanbiedt ) steeds een voorstelling zal blijven van Price en TaxPercentage ( eventueel inclusief hun validaties of bewerkingen ). Dit zal steeds zo blijven omdat de betekenis van die members gegarandeerd zou moeten zijn, dit kan je niet zeggen van de gerelateerde velden die gebruikt worden voor de interne opslag, deze kunnen eender welke voorstelling zijn, die nog gevalideerd of gemanipuleerd kunnen worden alvorens tot hetgeen te komen dat echt de prijs of de tax voorstelt. Zelfs al gaat het niet om een publieke property dan zal het om dezelfde redenen doorgaans nog altijd interessanter zijn deze te gebruiken in plaats van een eventueel gerelateerd veld.
In dit voorbeeld merk je ook dat een property-constructie niet noodzakelijk moet gekoppeld worden aan een veld. Binnen de implementatie van de getter en de setter kan men eender welke code uitvoeren.
Hoewel deze PriceIncludingTax te verwezelijken was via een ReadOnly Property kunnen we hiervoor ook een getfunctie gebruiken, dit is ook wat de coding guidelines ons aanraden in het geval dat de implementatie meer inhoud dan enkel het ophalen van een veldwaarde : Visual Basic 2010 Broncode Namespace FunctionInsteadOfReadOnlyPropertyExample Class Product Private m_Price As Decimal Public Property Price() As Decimal Get Price = m_Price End Get Set( ByVal value As Decimal) m_Price = value End Set End Property Private m_TaxPercentage As Decimal Public Property TaxPercentage() As Decimal Get TaxPercentage = m_TaxPercentage End Get Set( ByVal value As Decimal) m_TaxPercentage = value End Set End Property Public Function GetPriceIncludingTax() As Decimal GetPriceIncludingTax = Price * (1 + (TaxPercentage / 100)) End Function End Class Module Client Sub Main() Dim product1 As Product = New Product product1.Price = 100 product1.TaxPercentage = 8 Console.WriteLine(product1.GetPriceIncludingTax()) Console.ReadLine() End Sub End ModuleEnd NamespaceDownload Visual Basic 2010 Broncode Download Visual C# Sourcecode
Console Application Output 108,00 boven
9.4.2. ReadOnly FieldsOok velden kunnen ReadOnly gedeclareerd worden.
Aan deze kan enkel een waarde worden toegewezen in de constructor.
Dit wordt gebruikt voor bevroren toestanden, niet te verwarren met constanten. Een bevroren toestand ( in tegenstelling tot een constante ) kan ingesteld worden at runtime ( enkel in de constructor ), maar zal daarna nooit meer van waarde veranderen ( net als een constante ).
Voor meer details over constructoren en ReadOnly velden, kan je het artikel over constructoren raadplegen. boven
9.4.3. WriteOnly PropertyNaast ReadOnly Property kan men ook een WriteOnly Property opstellen, deze heeft dan geen getter. Maar abstractiegewijs zijn er bijna geen situaties waarin dit bruikbaar is. Je zou je kunnen afvragen voor welke eigenschap het nuttig kan zijn het toe te laten een bepaalde waarde in te stellen, maar niet toe te laten deze waarde ( die toch reeds gekend is omdat de client deze heeft ingesteld ) op te vragen. Een WriteOnly Property is dan ook zeldzaam en getuigd meestal van een povere abstractie, ik verkies dan ook hiervan geen voorbeeld op te nemen. boven
9.4.4. OefeningOpgave : Maak een klasse waarvan objecten een abstractie vormen van een eenvoudige bankrekening.
Een bankrekening heeft een bepaald saldo ( dat onbeperkt positief of negatief ) kan zijn. Initiëel ( voor een nieuwe rekening ) is het saldo nul.
Van een bankrekening kan een bepaald bedrag worden afgehaald, en op een bankreking kan een bepaald bedrag worden gestort.
Een bedrag van een bankrekening kan ook worden overschreven naar een ( andere ) bankrekening. Overschrijven wordt beschouwd als het afhalen van een rekening en storten op een ( andere ) rekening. Oplossing : Visual Basic 2010 Broncode Module BankAccountTestFixture Sub Main() Dim bankAccount1 As BankAccount = New BankAccount Console.WriteLine(bankAccount1.Balance = 0) bankAccount1.Deposit(100) Console.WriteLine(bankAccount1.Balance = 100) bankAccount1.Withdraw(60) Console.WriteLine(bankAccount1.Balance = 40) Dim bankAccount2 As BankAccount = New BankAccount bankAccount1.Transfer(50, bankAccount2) Console.WriteLine(bankAccount1.Balance = -10) Console.WriteLine(bankAccount2.Balance = 50) Console.ReadLine() End SubEnd ModuleClass BankAccount Private m_Balance As Decimal Public ReadOnly Property Balance() As Decimal Get Balance = m_Balance End Get End Property Public Sub Deposit( ByVal amount As Decimal) m_Balance += amount End Sub Public Sub Withdraw( ByVal amount As Decimal) m_Balance -= amount End Sub Public Sub Transfer( ByVal amount As Decimal, ByVal target As BankAccount) Withdraw(amount) target.Deposit(amount) End SubEnd ClassDownload Visual Basic 2010 Broncode Download Visual C# Sourcecode
Console Application Output True
True
True
True
True
Dit artikel is gepubliceerd op zondag 31 juli 2011 op vbvoorbeelden, bezoek de website voor een recente versie van dit artikel of andere artikels.
|