|
|
 |
|
|
|
|
|
|
|
|
Visual Basic 2008 9.0 .NET Examples and Ebook
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Caching versus Calculation
| An alternative to calculation the value of a derived attribute in the getfunction GetPriceIncludingTax is to calculate that value in the setters of the base-state properties ( Price en Tax ). That value can then be cached away ( in m_PriceIncludingTax ), and then simple be collected when asked for ( in the getfunction GetPriceIncludingTax. |
| Namespace Example1
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
setPriceIncludingTax()
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
setPriceIncludingTax()
End Set
End Property
Private m_PriceIncludingTax As Decimal
Public Function GetPriceIncludingTax() As Decimal
GetPriceIncludingTax = m_PriceIncludingTax
End Function
Private Sub setPriceIncludingTax()
m_PriceIncludingTax = Price * (1 + (TaxPercentage / 100))
End Sub
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 Module
End Namespace Download Broncode |
| This can be an advantage when querying/getting GetPriceIncludingTax happens more often then setting Price or Tax. Less calculations have to be made.
But watch out, there to avoid making to many assumptions about the way objects of your classes will be used, like the order an frequency the members will be called. Always try to design classes that can be used efficiently in all kinds of situations,
An obvious disadvantage of the method ( caching the derived values ) is that the logic about how and when the derived values have to be calculated is spread over different members of the class, and consequently will be more complex to maintain or scale. Often lots of synchronization code needs to be added.
Chose wisely whether or not to cache a derived state, and be aware of the consequences of your decision.
Some coding guidelines suggest using a 'Property' when you're accessing a field directly, in this case a 'ReadOnly Property'. Following these guidelines we change the class to : |
| Namespace Example2
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
setPriceIncludingTax()
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
setPriceIncludingTax()
End Set
End Property
Private m_PriceIncludingTax As Decimal
Public ReadOnly Property PriceIncludingTax() As Decimal
Get
PriceIncludingTax = m_PriceIncludingTax
End Get
End Property
Private Sub setPriceIncludingTax()
m_PriceIncludingTax = Price * (1 + (TaxPercentage / 100))
End Sub
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 Module
End Namespace Download Broncode |
Up
Unit Tests
| For each of the following classes a "test fixture" is created.
The members of each class ( each "unit" ) is tested for the expected behaviour.
These fixtures make an instance of the class that has to be tested, and will test the command ( procedures ) using the queries ( functions ).
These tests define the behaviour we expect from the classes.
It's useful to define the tests before defining the classes ( "testdriven development" ). By doing this you reflect on the abstraction, the public interface and the expected behaviour of these classes. Once the tests are defined, you can easily start implementing your classes until all tests run successfully. |
Up
Exercises
| Task 1 :
Make it possible to create objects that represent an addition. An addition has two values ( each settable and queryable ) and a result ( queryable ). |
| Namespace Exercise1
Class Addition
Private m_Value1 As Integer
Public Property Value1() As Integer
Get
Value1 = m_Value1
End Get
Set(ByVal value As Integer)
m_Value1 = value
End Set
End Property
Private m_Value2 As Integer
Public Property Value2() As Integer
Get
Value2 = m_Value2
End Get
Set(ByVal value As Integer)
m_Value2 = value
End Set
End Property
Public Function GetResult() As Integer
GetResult = Value1 + Value2
End Function
End Class
Module AdditionTestFixture
Sub Main()
Dim addition1 As Addition = New Addition
Console.WriteLine(addition1.Value1 = 0)
Console.WriteLine(addition1.Value2 = 0)
Console.WriteLine(addition1.GetResult() = 0)
addition1.Value1 = 1
Console.WriteLine(addition1.Value1 = 1)
Console.WriteLine(addition1.Value2 = 0)
Console.WriteLine(addition1.GetResult() = 1)
addition1.Value2 = 2
Console.WriteLine(addition1.Value1 = 1)
Console.WriteLine(addition1.Value2 = 2)
Console.WriteLine(addition1.GetResult() = 3)
Console.ReadLine()
End Sub
End Module
End Namespace Download Broncode |
| Output : True
True
True
True
True
True
True
True
True |
| It may seem unnecessary to test if property 'Value2' is 0 (2) after setting property 'Value1' (1). Still it is useful to test if setting 'Value1' doesn't ( "accidentally" ) alter 'Value2'. |
| Make it possible to create lamp objects. A simple press button on each lamp can be used to make the lamp give light, or to stop the lamp from giving light. |
| Namespace Exercise2
Class Lamp
Private m_GivesLight As Boolean
Public ReadOnly Property GivesLight() As Boolean
Get
GivesLight = m_GivesLight
End Get
End Property
Public Sub PressButton()
m_GivesLight = Not m_GivesLight
End Sub
End Class
Module LampTestFixture
Sub Main()
Dim lamp1 As Lamp = New Lamp
Console.WriteLine(lamp1.GivesLight = False)
lamp1.PressButton()
Console.WriteLine(lamp1.GivesLight = True)
lamp1.PressButton()
Console.WriteLine(lamp1.GivesLight = False)
Console.ReadLine()
End Sub
End Module
End Namespace Download Broncode |
| Make it possible to create counter objects. Each counter has a queryable value and a stepvalue ( settable and queryable ). To manipulate the value of a counter you must be able to give the counter the commands to raise ( value incremented with 1 ) or to lower ( value decremented with 1 ) itself. The value is initially 0, the stepvalue 1. |
| Namespace Exercise3
Class Counter
Private m_Value As Integer
Public Property Value() As Integer
Get
Value = m_Value
End Get
Set(ByVal value As Integer)
m_Value = value
End Set
End Property
Private m_StepValue As Integer = 1
Public Property StepValue() As Integer
Get
StepValue = m_StepValue
End Get
Set(ByVal value As Integer)
m_StepValue = value
End Set
End Property
Public Sub Raise()
Value += StepValue
End Sub
Public Sub Lower()
Value -= StepValue
End Sub
End Class
Module CounterTestFixture
Sub Main()
Dim counter1 As Counter = New Counter
Console.WriteLine(counter1.Value = 0)
Console.WriteLine(counter1.StepValue = 1)
counter1.Value = 10
Console.WriteLine(counter1.Value = 10)
Console.WriteLine(counter1.StepValue = 1)
counter1.StepValue = 5
Console.WriteLine(counter1.Value = 10)
Console.WriteLine(counter1.StepValue = 5)
counter1.Raise()
Console.WriteLine(counter1.Value = 15)
Console.WriteLine(counter1.StepValue = 5)
counter1.Lower()
Console.WriteLine(counter1.Value = 10)
Console.WriteLine(counter1.StepValue = 5)
Console.ReadLine()
End Sub
End Module
End Namespace Download Broncode |
| Output : True
True
True
True
True
True
True
True
True
True |
| Make a class that simulates a simple robot. The robot can move over a coordinate system ( X and Y coordinates ) in horizontal or vertical direction.
A robot can only given the command to rotate ( always 90 degrees clockwise ) and to place a step ( which shifts the robot 1 unit over then X- or Y-axis ).
Make a robot queryable for it X and Y position.
Initially the robot is in oriented in north direction and is on X position 0 and Y position 0. |
| Namespace Exercise4
Class Robot
Private m_X As Integer
Public ReadOnly Property X() As Integer
Get
X = m_X
End Get
End Property
Private m_Y As Integer
Public ReadOnly Property Y() As Integer
Get
Y = m_Y
End Get
End Property
Private m_Direction As Integer
Public Sub Rotate()
m_Direction += 1
If m_Direction > 3 Then m_Direction = 0
End Sub
Public Sub PlaceStep()
Select Case m_Direction
Case 0
m_Y += 1
Case 1
m_X += 1
Case 2
m_Y -= 1
Case 3
m_X -= 1
End Select
End Sub
End Class
Module RobotTestFixture
Public Sub Main()
Dim robot1 As Robot = New Robot
Console.WriteLine(robot1.X = 0)
Console.WriteLine(robot1.Y = 0)
robot1.PlaceStep()
Console.WriteLine(robot1.X = 0)
Console.WriteLine(robot1.Y = 1)
robot1.PlaceStep()
Console.WriteLine(robot1.X = 0)
Console.WriteLine(robot1.Y = 2)
robot1.Rotate()
Console.WriteLine(robot1.X = 0)
Console.WriteLine(robot1.Y = 2)
robot1.PlaceStep()
Console.WriteLine(robot1.X = 1)
Console.WriteLine(robot1.Y = 2)
robot1.Rotate()
robot1.PlaceStep()
Console.WriteLine(robot1.X = 1)
Console.WriteLine(robot1.Y = 1)
robot1.Rotate()
robot1.PlaceStep()
Console.WriteLine(robot1.X = 0)
Console.WriteLine(robot1.Y = 1)
robot1.Rotate()
robot1.PlaceStep()
Console.WriteLine(robot1.X = 0)
Console.WriteLine(robot1.Y = 2)
Console.ReadLine()
End Sub
End Module
End Namespace Download Broncode |
| Output : True
True
True
True
True
True
True
True
True
True
True
True
True
True
True
True |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|