Solved

How can I change this code example to achieve a more flexible alternative?

Posted on 2014-11-12
6
94 Views
Last Modified: 2014-11-12
I am using a cache class which stores sets of data held within classes for different periods.  I've been trying to enhance this to include sets of data from other areas.  I would like to reuse much of the code which operates and keeps the Cache up to date.
In the example below you will see that the AddData and Add methods implement the SalesData type of class.
How would I make the AddData and Add methods work irrespective of the Class type, provided both use a start and end date constructor.
I realise I can repeat each method in each inheriting child class but in my implementation these methods are quite a bit longer and I am seeking where possible to keep the code reusable and manageable.
I am thinking that polymorphism and interfaces may play a part but I don't have the understanding to apply them.

Public Class GenericCache
    Inherits System.Collections.CollectionBase
    Dim pStartDate, pEndDate As DateTime
    Private Sub Add(ByVal cSalesData As SalesData)
        Me.List.Add(cSalesData)
    End Sub
    Sub AddData()
        Me.Add(New SalesData("2001-01-01", "2001-01-02"))
        Me.Add(New SalesData("2001-01-02", "2001-01-03"))
        Me.Add(New SalesData("2001-01-04", "2001-01-05"))
    End Sub    
End Class
Public Class CachedSalesData
    Inherits GenericCache
    'properties and methods particular to SalesCache
End Class

Public Class CachedOrdersData
    Inherits GenericCache
    'properties and methods particular to OrdersCache
End Class

Public Class SalesData
    Public Sub New(StartDate As DateTime, EndDate As DateTime)
        'Looks up Sales for dates supplied
    End Sub
End Class

Public Class OrdersData
    Public Sub New(StartDate As DateTime, EndDate As DateTime)
        'Looks up Orders for dates supplied
    End Sub
End Class

Open in new window

0
Comment
Question by:dgloveruk
  • 2
  • 2
  • 2
6 Comments
 
LVL 17

Expert Comment

by:OriNetworks
ID: 40438000
Instead of stricly delcaring the incoming object as SalesData you can delcare it as a generic Object
 Private Sub Add(ByVal cSalesData As Object)

Depending on how you select the data to add and retireve you can check the object type and/or Cast the object to the correct type. e.g. obj.GetType()
0
 

Author Comment

by:dgloveruk
ID: 40438028
Something I wanted to do was that in the CachedSalesData class I would run adddata and it would effectively do this :
 Me.Add(New SalesData("2001-01-01", "2001-01-02"))
but if I ran adddata on a CachedOrdersData class it would use the same adddata sub but do this :
 Me.Add(New OrderData("2001-01-01", "2001-01-02"))

Note that I can't syntactically use  Me.Add(New Object("2001-01-01", "2001-01-02"))
0
 
LVL 17

Accepted Solution

by:
OriNetworks earned 500 total points
ID: 40438046
Correct. You would still use Me.Add(New SalesData(.... or New OrderData

Private Sub Add(ByVal cSalesData As SalesData)
        Me.List.Add(cSalesData)
    End Sub

Open in new window

would change to
Private Sub Add(ByVal cGenericData As Object)
        Me.List.Add(cGenericData)
    End Sub

Open in new window


I like to keep things separate so I personally would keep the objects in separate lists but this would be the way to do it with one generic list of dynamic objects.
0
Courses: Start Training Online With Pros, Today

Brush up on the basics or master the advanced techniques required to earn essential industry certifications, with Courses. Enroll in a course and start learning today. Training topics range from Android App Dev to the Xen Virtualization Platform.

 

Author Closing Comment

by:dgloveruk
ID: 40438062
Ok thank you!
0
 
LVL 33

Expert Comment

by:it_saige
ID: 40438128
I never recommend using a loose Object declaration unless you absolutely have to.  It breaks type safety.

If I am understanding your requirements, you could do something like this:
Class PolymorphismExample
	Public Class GenericCache
		Inherits System.Collections.CollectionBase
		Private Sub Add(ByVal cCacheData As ICacheData)
			Me.List.Add(cCacheData)
		End Sub

		Sub AddData()
			Me.Add(New SalesData("2001-01-01", "2001-01-02"))
			Me.Add(New OrderData("2001-01-01", "2001-01-02"))
			Me.Add(New SalesData("2001-01-02", "2001-01-03"))
			Me.Add(New OrderData("2001-01-02", "2001-01-03"))
			Me.Add(New SalesData("2001-01-04", "2001-01-05"))
			Me.Add(New OrderData("2001-01-03", "2001-01-04"))
		End Sub
	End Class

	Public Interface ICacheData
		Property StartDate() As DateTime
		Property EndDate() As DateTime
	End Interface

	Public Class SalesData
		Implements ICacheData
		Private pStartDate As DateTime
		Private pEndDate As DateTime

		Public Property EndDate As Date Implements ICacheData.EndDate
			Get
				Return pEndDate
			End Get
			Set(ByVal value As Date)
				If Not value.Equals(pEndDate) Then
					pEndDate = value
				End If
			End Set
		End Property

		Public Property StartDate As Date Implements ICacheData.StartDate
			Get
				Return pStartDate
			End Get
			Set(ByVal value As Date)
				If Not value.Equals(pEndDate) Then
					pStartDate = value
				End If
			End Set
		End Property

		Public Sub New(ByVal StartDate As String, ByVal EndDate As String)
			If Not DateTime.TryParse(StartDate, Me.StartDate) Then
				Throw New ArgumentException("StartDate must be a valid DateTime value", "StartDate")
			End If

			If Not DateTime.TryParse(EndDate, Me.EndDate) Then
				Throw New ArgumentException("EndDate must be a valid DateTime value", "EndDate")
			End If
		End Sub

		Public Sub New(ByVal StartDate As DateTime, ByVal EndDate As String)
			If Not DateTime.TryParse(EndDate, Me.EndDate) Then
				Throw New ArgumentException("EndDate must be a valid DateTime value", "EndDate")
			End If

			Me.StartDate = StartDate
		End Sub

		Public Sub New(ByVal StartDate As String, ByVal EndDate As DateTime)
			If Not DateTime.TryParse(StartDate, Me.StartDate) Then
				Throw New ArgumentException("StartDate must be a valid DateTime value", "StartDate")
			End If

			Me.EndDate = EndDate
		End Sub

		Public Sub New(ByVal StartDate As DateTime, ByVal EndDate As DateTime)
			Me.StartDate = StartDate
			Me.EndDate = EndDate
		End Sub
	End Class

	Public Class OrderData
		Implements ICacheData
		Private pStartDate As DateTime
		Private pEndDate As DateTime

		Public Property EndDate As Date Implements ICacheData.EndDate
			Get
				Return pEndDate
			End Get
			Set(ByVal value As Date)
				If Not value.Equals(pEndDate) Then
					pEndDate = value
				End If
			End Set
		End Property

		Public Property StartDate As Date Implements ICacheData.StartDate
			Get
				Return pStartDate
			End Get
			Set(ByVal value As Date)
				If Not value.Equals(pEndDate) Then
					pStartDate = value
				End If
			End Set
		End Property

		Public Sub New(ByVal StartDate As String, ByVal EndDate As String)
			If Not DateTime.TryParse(StartDate, Me.StartDate) Then
				Throw New ArgumentException("StartDate must be a valid DateTime value", "StartDate")
			End If

			If Not DateTime.TryParse(EndDate, Me.EndDate) Then
				Throw New ArgumentException("EndDate must be a valid DateTime value", "EndDate")
			End If
		End Sub

		Public Sub New(ByVal StartDate As DateTime, ByVal EndDate As String)
			If Not DateTime.TryParse(EndDate, Me.EndDate) Then
				Throw New ArgumentException("EndDate must be a valid DateTime value", "EndDate")
			End If

			Me.StartDate = StartDate
		End Sub

		Public Sub New(ByVal StartDate As String, ByVal EndDate As DateTime)
			If Not DateTime.TryParse(StartDate, Me.StartDate) Then
				Throw New ArgumentException("StartDate must be a valid DateTime value", "StartDate")
			End If

			Me.EndDate = EndDate
		End Sub

		Public Sub New(ByVal StartDate As DateTime, ByVal EndDate As DateTime)
			Me.StartDate = StartDate
			Me.EndDate = EndDate
		End Sub
	End Class

	Shared Sub Main()
		Try
			Dim cache As New GenericCache()
			cache.AddData()
			For Each item As ICacheData In cache
				Console.WriteLine(String.Format("Cache Item Type: {0}; Start Date: {1:MM/dd/yyyy}; End Date: {2:MM/dd/yyyy}", item.GetType(), item.StartDate, item.EndDate))
			Next
		Catch e As Exception
			Console.WriteLine(e.ToString())
		End Try
		Console.ReadLine()
	End Sub
End Class

Open in new window


Produces the following output:Capture.JPG
0
 
LVL 33

Expert Comment

by:it_saige
ID: 40438363
A word on why it breaks type safety.  Imagine 6 months from now, you (or someone else) add a new class FooData but do not implement FooData with a StartDate and/or EndDate, FooData can still be added to the cache because FooData *is* an Object but now you have to check to see if FooData has a StartDate and EndDate (per your requirements) or a call to the returned Object to pull the StartDate and/or EndDate will end in an exception.

Example:
Class PolymorphismExample
	Public Class GenericCache
		Inherits System.Collections.CollectionBase
		Private Sub Add(ByVal cCacheData As ICacheData)
			Me.List.Add(cCacheData)
		End Sub

		Private Sub Add(ByVal cCachData As Object)
			Me.List.Add(cCachData)
		End Sub

		Sub AddData()
			Me.Add(New SalesData("2001-01-01", "2001-01-02"))
			Me.Add(New OrderData("2001-01-01", "2001-01-02"))
			Me.Add(New SalesData("2001-01-02", "2001-01-03"))
			Me.Add(New OrderData("2001-01-02", "2001-01-03"))
			Me.Add(New SalesData("2001-01-04", "2001-01-05"))
			Me.Add(New OrderData("2001-01-03", "2001-01-04"))
			Me.Add(New FooData())
		End Sub
	End Class

	Public Interface ICacheData
		Property StartDate() As DateTime
		Property EndDate() As DateTime
	End Interface

	Public Class SalesData
		Implements ICacheData
		Private pStartDate As DateTime
		Private pEndDate As DateTime

		Public Property EndDate As Date Implements ICacheData.EndDate
			Get
				Return pEndDate
			End Get
			Set(ByVal value As Date)
				If Not value.Equals(pEndDate) Then
					pEndDate = value
				End If
			End Set
		End Property

		Public Property StartDate As Date Implements ICacheData.StartDate
			Get
				Return pStartDate
			End Get
			Set(ByVal value As Date)
				If Not value.Equals(pEndDate) Then
					pStartDate = value
				End If
			End Set
		End Property

		Public Sub New(ByVal StartDate As String, ByVal EndDate As String)
			If Not DateTime.TryParse(StartDate, Me.StartDate) Then
				Throw New ArgumentException("StartDate must be a valid DateTime value", "StartDate")
			End If

			If Not DateTime.TryParse(EndDate, Me.EndDate) Then
				Throw New ArgumentException("EndDate must be a valid DateTime value", "EndDate")
			End If
		End Sub

		Public Sub New(ByVal StartDate As DateTime, ByVal EndDate As String)
			If Not DateTime.TryParse(EndDate, Me.EndDate) Then
				Throw New ArgumentException("EndDate must be a valid DateTime value", "EndDate")
			End If

			Me.StartDate = StartDate
		End Sub

		Public Sub New(ByVal StartDate As String, ByVal EndDate As DateTime)
			If Not DateTime.TryParse(StartDate, Me.StartDate) Then
				Throw New ArgumentException("StartDate must be a valid DateTime value", "StartDate")
			End If

			Me.EndDate = EndDate
		End Sub

		Public Sub New(ByVal StartDate As DateTime, ByVal EndDate As DateTime)
			Me.StartDate = StartDate
			Me.EndDate = EndDate
		End Sub
	End Class

	Public Class OrderData
		Implements ICacheData
		Private pStartDate As DateTime
		Private pEndDate As DateTime

		Public Property EndDate As Date Implements ICacheData.EndDate
			Get
				Return pEndDate
			End Get
			Set(ByVal value As Date)
				If Not value.Equals(pEndDate) Then
					pEndDate = value
				End If
			End Set
		End Property

		Public Property StartDate As Date Implements ICacheData.StartDate
			Get
				Return pStartDate
			End Get
			Set(ByVal value As Date)
				If Not value.Equals(pEndDate) Then
					pStartDate = value
				End If
			End Set
		End Property

		Public Sub New(ByVal StartDate As String, ByVal EndDate As String)
			If Not DateTime.TryParse(StartDate, Me.StartDate) Then
				Throw New ArgumentException("StartDate must be a valid DateTime value", "StartDate")
			End If

			If Not DateTime.TryParse(EndDate, Me.EndDate) Then
				Throw New ArgumentException("EndDate must be a valid DateTime value", "EndDate")
			End If
		End Sub

		Public Sub New(ByVal StartDate As DateTime, ByVal EndDate As String)
			If Not DateTime.TryParse(EndDate, Me.EndDate) Then
				Throw New ArgumentException("EndDate must be a valid DateTime value", "EndDate")
			End If

			Me.StartDate = StartDate
		End Sub

		Public Sub New(ByVal StartDate As String, ByVal EndDate As DateTime)
			If Not DateTime.TryParse(StartDate, Me.StartDate) Then
				Throw New ArgumentException("StartDate must be a valid DateTime value", "StartDate")
			End If

			Me.EndDate = EndDate
		End Sub

		Public Sub New(ByVal StartDate As DateTime, ByVal EndDate As DateTime)
			Me.StartDate = StartDate
			Me.EndDate = EndDate
		End Sub
	End Class

	Public Class FooData
		Public Overrides Function ToString() As String
			Return "I am an evil foo data object; prepare for an exception"
		End Function
	End Class

	Shared Sub Main()
		Try
			Dim cache As New GenericCache()
			cache.AddData()
			For Each item In cache
				Console.WriteLine(String.Format("Cache Item Type: {0}; Start Date: {1:MM/dd/yyyy}; End Date: {2:MM/dd/yyyy}", item.GetType(), If(TypeOf item Is ICacheData, TryCast(item, ICacheData).StartDate, item), If(TypeOf item Is ICacheData, TryCast(item, ICacheData).EndDate, item)))
			Next
		Catch e As Exception
			Console.WriteLine(e.ToString())
		End Try
		Console.ReadLine()
	End Sub

Open in new window


Produces the following output:Capture.JPG
-saige-
0

Featured Post

Live: Real-Time Solutions, Start Here

Receive instant 1:1 support from technology experts, using our real-time conversation and whiteboard interface. Your first 5 minutes are always free.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Title # Comments Views Activity
Get hold of longitude and latitude in iframe string 11 45
VB.Net - KeyPress Event 4 36
VB.Net - TypeInitializer Error 25 26
VB.Net Report Printing Issue 3 31
Calculating holidays and working days is a function that is often needed yet it is not one found within the Framework. This article presents one approach to building a working-day calculator for use in .NET.
It was really hard time for me to get the understanding of Delegates in C#. I went through many websites and articles but I found them very clumsy. After going through those sites, I noted down the points in a easy way so here I am sharing that unde…
Although Jacob Bernoulli (1654-1705) has been credited as the creator of "Binomial Distribution Table", Gottfried Leibniz (1646-1716) did his dissertation on the subject in 1666; Leibniz you may recall is the co-inventor of "Calculus" and beat Isaac…
A short tutorial showing how to set up an email signature in Outlook on the Web (previously known as OWA). For free email signatures designs, visit https://www.mail-signatures.com/articles/signature-templates/?sts=6651 If you want to manage em…

785 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question