At the moment I'm trying to create a kind of model in vb.net which can be used to create/fetch database entrys.
I created a main class Model with a shared function to fetch the datasets, e.g. Model.find().
Now I'd like to create Classes which inherit the main Model-Class, e.g. a separate one for users: UserModel.find() => "SELECT * FROM users".
What I need now is to find a way to tell the Class which table it should use. I thought about an abstract String "table" which is a constant in each "child-model", but how could this be implemented as it's not possible to override shared members?
Thanks in advance!
Edit: Maybe this will make it a little clearer what I mean:
Public Class Model
Public Shared _controller As Controller
Public Shared table As String
Protected Shared tableFields As String()
Shared reader As Npgsql.NpgsqlDataReader
Public Shared Function find()
Dim a As ArrayList = New ArrayList
'Test if the tablefields are already known to the class, if not, get them
If tableFields Is Nothing Then
getTableFields()
End If
Dim query As String = "SELECT " + String.Join(", ", tableFields) + " FROM " + table
reader = _controller.executeReader(query)
While reader.Read
o = New Model
Dim v As New Hashtable
For Each field In tableFields
v(field) = reader(field)
Next
o.values = v
a.Add(o)
End While
reader.Close()
Return DirectCast(a.ToArray(GetType(Model)), Model())
End Function
Public values As Hashtable
Public Sub New()
End Sub
End Class
So I want a shared method which finds all database entries and gives back an array of instances of its own type, e.g. Model().
That's why I wanted to keep the find-method shared and not bound to an instance.
I think you could use Generics. Here I´ve pasted an example
All the classes in your domain could inherit from Entity class
Public MustInherit Class Entity
'...
End Class
Your Model class, with your method Find
Public Class Model
Public Shared Sub Find(Of T As Entity)()
' You could know the name of T to find the table
Dim tableName As String = GetType(T).Name
'...
End Sub
End Class
One class of your domain, for example: User class
Public Class User
Inherits Entity
' ...
End Class
And finally, an example of how could you instantiate the Find method
Model.Find(Of User)()
'...
I dunno if this is what you mean, do you find this helpfull?
You could make your main class abstract and each subclass will have to return its "own" table name via its own implementation (e.g. getTableName). This way, you would only have to maintain you method logic in the main class.
It is common to use the Singleton design pattern in such cases: create an instance method, overridden by inheriting classes. Each inheriting class should have that instance method return a Singleton object related to that class.
Here is one way of doing it:
MustInherit Class BaseClass
Public MustOverride Function getTableName() As String
End Class
Class Class1
Inherits BaseClass
Private Shared TableName As String = "myTable1"
Public Overrides Function getTableName() As String
Return TableName
End Function
End Class
Class Class2
Inherits BaseClass
Private Shared TableName As String = "myTable2"
Public Overrides Function getTableName() As String
Return TableName
End Function
End Class
EDIT: a whole different approach.
You can have the base class hold some dictionary, which relates class types (or type names) with the correct table:
Class BaseClass
Private Shared myDictionary As New Collections.Generic.Dictionary(Of Type, String)
Friend Shared Sub RegisterType(ByVal childType As Type, ByVal tableName As String)
myDictionary.Add(childType, tableName)
End Sub
Public Shared Function getTableName(ByVal childType As Type) As String
Return myDictionary.Item(childType)
End Function
End Class
Class Class1
Shared Sub New()
BaseClass.RegisterType(GetType(Class1), "table1")
End Sub
End Class
Class Class2
Shared Sub New()
BaseClass.RegisterType(GetType(Class2), "table2")
End Sub
End Class
Shared (static) objects or object members can't be inherited or overrided. Inheritence is for instance of an object. Since you do not have to instantiate a static class you can't inherit from it. The same with the methods. A static method shouldn't be virtual (Overridable in VB) as it defines a method that perform tasks with no instance of the class. Then this makes it impossible to use instance fields or properties within a static (Shared in VB) method. This is a bad design trying so.
In fact, every static (Shared) classes should be marked as NotInheritable in VB, and defining the default empty constructor only. This is a leak from VB in regards of OOP concepts.
Related
I'm looking for suggestions on how to create a custom collection class in VB.Net, to contain instances of a custom object class. There is so much information on the topic that I'm not sure which direction to go in, and custom collections are new to me.
The collection needs are as follows:
collection should be read-only, it and its objects cannot be modified.
collection will always be a fixed size.
because of above two items, add, remove, count, clear, etc aren't needed.
will create & manage all object instances itself at instantiation.
should have a default property like "Item". (?)
should be enumerable, so For-Each can be used on it.
Here is a simplified outline of what I've pieced together so far:
Class Bay
Private ID As Integer
Private p_String As String
Private p_Aisle As Integer
...etc...
...getters, setters, & subs...
End Class
Class Bays
Inherits ...something...
Implements ....somethingelse... (?)
Public ReadOnly MyCollection(5094) as SomeCollectionType (Of Bay)
Private LastUpdate As Date
Private SystemStatus as Integer
Public Sub New()
...instantiate all objects in collection...
End Sub
...properties...
End Class
This is the sort of thing you can do:
Public Class Thing
'...
End Class
Public Class ReadOnlyThingCollection
Inherits ReadOnlyCollection(Of Thing)
Public Sub New()
MyBase.New(GetItems())
End Sub
Private Shared Function GetItems() As IList(Of Thing)
'Generate items as appropriate.
Return {New Thing, New Thing, New Thing}
End Function
End Class
I collected different derived class instances using a List(Of Interface).
And naturally I only can access the Interfaced methods using iteration.
Public Class Base
Public Sub Work_inBase()
End Sub
End Class
'--------------------------
Public Interface MyIFC
Sub Work()
End Interface
'--------------------------
Public Class Child1
Inherits Base
Implements MyIFC
Public Sub Work() Implements MyIFC.Work
End Sub
End Class
'--------------------------
Public Class Child2
Inherits Base
Implements MyIFC
Public Sub Work() Implements MyIFC.Work
End Sub
End Class
'--------------------------
Public Sub MainProgram()
Dim C1 As New Child1()
Dim C2 As New Child2()
Dim MyList As New List(Of MyIFC)
MyList.Add( C1 )
MyList.Add( C2 )
MyList(0).Work() >>> OK because it was interfaced
MyList(0).Work_inBase() >>> does not work, cannot access to base
End Sub
Is there any other way to access to base class methods or members (which will be very large)??? Maybe different class design is required???
Thank you (vb is prefered, but I can read c# code equally too)
Obviously there is no way to know that an arbitrary List(Of MyIFC) actually contains members that are or do inherit type Base, so there's no reason that there should be any standard functionality that would give you items of that type. If you know for a fact that the items will be that type though, you can simply cast as that type when they come out, e.g.
DirectCast(MyList(0), Base).Work_inBase()
Of course, once you have a reference of type Base then you can't access members of MyIFC because Base doesn't implement that interface. Your example is very contrived so there's no way for us to know whether there's a better design possible in your specific case.
I have a base class that I use with reflection to fill the fields of the derived classes, reading from the database.
Public MustInherit Class DaoBase : Implements IEquatable(Of DaoBase)
Sub New()
' Empty, hate to have it
End Sub
Sub New(reader As DbDataReader)
' Reads the DB and fills the instance fields
End Sub
' More stuff...
End Class
The derived classes usually have a non-default constructor to set its fields:
Public Class Customer
Inherits DaoBase
Public Sub New(
id As Integer,
description As String)
Me.id = id
Me.description = description
End Sub
End Class
Questions:
1) I don't like to have the empty constructor in the base class. It sits there unused and could create an object in an incorrect state. If I remove it, then the compiler gives an error because, missing the default constructor, the derived class constructor should call the only-one base class constructor.
2) I can't do new Customer(myReader) because that constructor is not in the derived class, even if it's in the base class. I have to explicitly declare it, which I don't like.
Public Class Customer
Inherits DaoBase
Public Sub New(
id As Integer,
description As String)
Me.id = id
Me.description = description
End Sub
Public Sub New(reader As DbDataReader)
MyBase.New(reader)
End Sub
End Class
If your base class is filling fields in the derived class, it sounds like you should be using an interface instead of what you're doing.
As for your questions, just because you don't like it doesn't make it wrong. But as one comment said, if you change the second New to:
Sub New(Optional reader as DbDataReader = Nothing)
then you fulfill the requirement to have an empty constructor and you can have it do the right thing when no reader is given.
In general, according to the OOP paradigm, my understanding of encapsulation basically says:
If a member is private, it can only be accessed by the class.
If a member is protected, it can only be accessed by the base class and any derived classes.
If a member is public, it can be accessed by anyone.
If I have a nested class, can I declare a property to be accessible only to that class and the parent class it's nested within? For example:
Public Class ContainerClass
Public Class NestedClass
Protected myInt As Integer ' <- this is what I am wondering about '
Protected myDbl As Double ' <- this is what I am wondering about '
Sub New()
myInt = 1
myDbl = 1.0
End Sub
End Class
Private myNestedObject As New NestedClass
' this function is illegal '
Public Sub GrowNestedObject(ByVal multiplier As Integer)
myNestedObject.myInt *= multiplier
myNestedObject.myDbl *= multiplier
End Sub
End Class
In the example, I cannot directly access myNestedObject.myInt or myNestedObject.myDbl from an instance of ContainerClass if those members are Private or Protected. But suppose I don't want to make them Public, because then they are TOO exposed: they can be altered from anywhere, not just within a ContainerClass object. Declaring them Friend would still be too weak as that would allow them to be altered from anywhere within the application.
Is there any way to accomplish what I am going for here? If not, can anyone think of a more sensible way to achieve something like this?
There is no way of doing this directly with a combination of accessibility modifiers.
The best way I can think of doing this is as follows. It involves an extra level of indirection.
Create a Nested Interface with Private accessibility. This will give only the Parent class and nested children access
Add the fields you want access to to that interface
Make the Nested class implement the interface
Make all of the implementations have private accessibility
Now the parent class and only the parent class will have access to those properties and methods.
For Example:
Class Parent
Private Interface Interface1
ReadOnly Property Field1() As Integer
End Interface
Public Class Nested1
Implements Interface1
Private ReadOnly Property Field1() As Integer Implements Interface1.Field1
Get
Return 42
End Get
End Property
End Class
Sub New()
Dim child As Interface1 = New Nested1
Dim x = child.Field1
End Sub
End Class
Based on JaredPar's answer, you could use a Private ChildClass but a Public Interface that reveals only what it sould show :
Public Class ParentClass
Public Interface IChildClass
ReadOnly Property i() As Integer
Sub SomeSub()
End Interface
Private Class ChildClass
Implements IChildClass
Public myInt As Integer
Public ReadOnly Property i() As Integer Implements IChildClass.i
Get
Return myInt
End Get
End Property
Public Sub SomeSub() Implements IChildClass.SomeSub
End Sub
End Class
Public Shared Function GetNewChild() As IChildClass
Dim myChild = New ChildClass()
myChild.myInt = 3
Return myChild
End Function
End Class
Usage :
Dim c As ParentClass.IChildClass = ParentClass.GetNewChild()
MessageBox.Show(c.i)
c.i = 2 ' Does not compile !
c.SomeSub()
I have the following sample code in a VB.NET console application. It compiles and works, but feels like a hack. Is there a way to define EmptyChild so that it inherits from Intermediate(Of T As Class) without using the dummy EmptyClass?
Module Module1
Sub Main()
Dim Child1 = New RealChild()
Child1.Content = New RealClass()
Dim Child2 = New EmptyChild()
Console.WriteLine("RealChild says: " & Child1.Test)
Console.WriteLine("EmptyChild says: " & Child2.Test)
Console.ReadLine()
End Sub
Public Class EmptyClass
End Class
Public Class RealClass
Public Overrides Function ToString() As String
Return "This is the RealClass"
End Function
End Class
Public MustInherit Class Base(Of T As Class)
Private _content As T = Nothing
Public Property Content() As T
Get
Return _content
End Get
Set(ByVal value As T)
_content = value
End Set
End Property
Public Overridable Function Test() As String
If Me._content IsNot Nothing Then
Return Me._content.ToString
Else
Return "Content not initialized."
End If
End Function
End Class
Public MustInherit Class Intermediate(Of T As Class)
Inherits Base(Of T)
'some methods/properties here needed by Child classes
End Class
Public Class RealChild
Inherits Intermediate(Of RealClass)
'This class needs all functionality from Intermediate.
End Class
Public Class EmptyChild
Inherits Intermediate(Of EmptyClass)
'This class needs some functionality from Intermediate,
' but not the Content as T property.
Public Overrides Function Test() As String
Return "We don't care about Content property or Type T here."
End Function
End Class
End Module
The other way to do this would be to move the generic code out of the Base class and then create 2 Intermediate classes like this:
Public MustInherit Class Intermediate
Inherits Base
'some methods/properties here needed by Child classes
End Class
Public MustInherit Class Intermediate(Of T As Class)
Inherits Intermediate
'implement generic Content property here
End Class
Then RealChild would inherit from the generic Intermediate and EmptyChild would inherit from the non-generic Intermediate. My problem with that solution is that the Base class is in a separate assembly and I need to keep the code that handles the generic type in that assembly. And there is functionality in the Intermediate class that does not belong in the assembly with the Base class.
Yes, you need to specify a type parameter when you inherit, or your EmptyChild must be generic as well. But, you don't have to dummy up a EmptyClass - just use Object as your type parameter:
Public Class EmptyClass
Inherits Intermediate(Of Object)
End Class