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

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

dgloverukAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

OriNetworksCommented:
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
dgloverukAuthor Commented:
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
OriNetworksCommented:
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

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
Cloud Class® Course: C++ 11 Fundamentals

This course will introduce you to C++ 11 and teach you about syntax fundamentals.

dgloverukAuthor Commented:
Ok thank you!
0
it_saigeDeveloperCommented:
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
it_saigeDeveloperCommented:
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
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Visual Basic.NET

From novice to tech pro — start learning today.

Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.