I have a bit of a design issue. I created a rate calculator as follows :
Public Interface ICalculator
Property PaymentTerm As Double
Function Calculate() As CommissionValues
ReadOnly Property CalculationRule As CalculationRuleEnum
End Interface
Public Interface IFlexibleRateCalculator
Inherits ICalculator
Property TransferRate As Decimal
End Interface
Public Interface IFixedRateCalculator
Inherits ICalculator
Property ContractRate As Decimal
End Interface
Public Interface IRateSettingBase
Property RateType As RateTypeEnum
ReadOnly Property Calculator As ICalculator
End Interface
Public MustInherit Class RateSetting
Implements IRateSettingBase
Public MustOverride ReadOnly Property Calculator() As ICalculator Implements IRateSettingBase.Calculator
I can do something like this:
dim ratevalues as RateValues = RateSetting().Calculator.Calculate()
Pretty simple. The problem is that each type of calculator has their own set of properties that need to be set in order for their Calculate() methods to work properly.
So I end up having to implement as follows
FlexibleRateCalculator
Implements IFlexibleRateCalculator
Private mRequestedRate As Decimal
Public Function Calculate() As RateValues Implements ICalculator.Calculate
FixedRateCalculator
Implements IFixedRateCalculator
Private mTransferRate As Decimal
Public Function Calculate() As RateValues Implements ICalculator.Calculate
What is the best way using generics and abstract classes to create a factory pattern that will generate a calculator of a specific type dynamically??
I need a very generic solution as many calculation rates will be added and modified all with their own parameters needed for the calculation logic. I want to be able to do this quickly and possibly control these rate calculation via db. FYI answers in C# or VB.Net are welcome :)
Thanks in advance!
Keep only the ICalculator interface and convert the more specific interfaces to classes. I can't think of a good reason why you would create a class just to store a variable, so I'm going to get rid of the RateSetting entirely.
Public Interface ICalculator
Property Rate As Double
Property PaymentTerm As Double
Function Calculate() As CommissionValues
ReadOnly Property CalculationRule As CalculationRuleEnum
End Interface
Public Class FlexibleRateCalculator : Implements ICalculator
Public Sub New(rate As Double)
Me.Rate = rate
End Sub
'
' ICalculator implementation goes here
'
End Class
Public Class FixedRateCalculator : Implements ICalculator
Public Sub New(rate As Double)
Me.Rate = rate
End Sub
'
' ICalculator implementation goes here
'
End Class
Public Enum RateType
Flexible = 1
Fixed = 2
End Enum
Public Class CalculatorFactory
Public Shared Function GetCalculator(rate As Double, type As RateType) As ICalculator
Select Case type
Case RateType.Flexible
Return New FlexibleRateCalculator(rate)
Case RateType.Fixed
Return New FixedRateCalculator(rate)
Case Else
Throw New ArgumentException
End Select
End Function
End Class
You create object instances by passing a rate and a rate type to the GetCalculator method. I don't know what you mean by CalculationRule, but if it's important to the end user then you should add it as an additional parameter.
You can easily add more calculator types that implement ICalculator, as long as you don't forget to update the select statement in the factory method.
EDIT: of course you can also set additional properties before returning an object instance. The point of this pattern however is to make sure that the end-user does not need to know about how Calculate() is implemented. If you want to make more specific factory methods for every calculator, it kind of defeats the purpose.
Are you familiar with any IoC containers? You should be able use the factory-type services they provide to generate you the appropriate types with appropriate parameters/properties based on a given type (enum, string, etc.)
If not, you could probably create a factory class that has a method that generates the appropriate type based on a parameter. This method could accept a ParamArray or other object that contains the properties needed to correctly set-up the calculator and then return it, via the ICalculator interface.
Related
I have two classes to handle database operations, one for MySQL (DBMySQL), and another for SQLite (DBSQLite). The user chooses which database system to use.
The functions within the classes have the same names, but are obviously slightly different to handle the variations in databases.
I would like to refer to the chosen class by one name throughout the application. I have set a global variable DB.
In a procedure I can: Dim DB as New DBMySQL (or DBSQLite). This works within the procedure, but not globally, but I can see all the functions when coding.
If I instead use: DB = New DBMySQL, this works globally, but no class functions are displayed when coding.
Any alternatives?
Use the concept of inheritance, and create a MustInherit class with MustOverride methods and/or properties.
Public MustInherit Class AbstractDB
Public MustOverride Function MyQuery(input As Object) As Object
Public MustOverride Sub MyUpdateMethod(input As Object)
End Class
Public Class DBMySQL
Inherits AbstractDB
Public Overrides Function MyQuery(input As Object) As Object
End Function
Public Overrides Sub MyUpdateMethod(input As Object)
End Sub
End Class
Public Class DBSQLite
Inherits AbstractDB
Public Overrides Function MyQuery(input As Object) As Object
End Function
Public Overrides Sub MyUpdateMethod(input As Object)
End Sub
End Class
Then, when you want to use your classes, make your DB global variable of type AbstractDB. You could then create either DBMySql or DBSQLite and assign it to your DB variable. The method names will all be the same, because they all inherit the same base class. But each derived class must fill out the content of those methods on its own.
Dim DB as AbstractDB = New DBMySQL
You could also use an interface.
Public Interface IRepository
' common functions of MySQL and SQLLiteclasses
End Interface
Public Class MySQLRepository
Implements IRepository
End Class
Public Class SQLLiteRepository
Implements IRepository
End Class
Public Function GetDB(userChoice As String) As IRepository
If userChoice = "MySQL" Then
Return New MySQLRepository()
Else
Return New SQLLiteRepository
End if
End Function
Dim DB As IRepository = GetDB(userChoice)
This is a basic implementation of the Repository pattern. The example in the link is in C#, but, as you're probably aware, it's not easy finding examples in VB. Fortunately, there are lots of C# to VB converters.
The abstract example Sean Skelly gave should also work. You may want to research the difference between abstract classes and interfaces.
I am trying to implement a derived interface in a class. My interfaces and class are similar to the following. The Namespaces relate to different projects that hold these interfaces and the class:
Namespace ns1
Public Interface IParent
Function myFunction() As Double
End Interface
End ns1
Namespace ns2
Public Interface IDerived
Inherits ns1.IParent
Overloads / Shadows Function myFunction(ByRef myObject as Object) As Double
End Interface
End ns2
Namespace ns3
Public Class myClass
Implements ns2.IDerived
Public Function myFunction(ByRef obj as Object) As Double Implements ns2.IDerived.myFunction
End Function
End ns3
In the derived interface, I am trying to overload the function in a way that when I implement the derived interface, I only have to implement the function as defined therein - as is done with the code above on "myClass". However, I am getting an error saying I have to also implement the function from the parent interface (with the empty argument list). The error exists regardless of my using Overloads or Shadows on the function in the derived interface - both cause the error.
Is there anyway to accomplish what I am trying to do - implement only the derived interface's function in my class - using interfaces? If there is not a way using interfaces, can anyone suggest an alternate way? We really need to use interfaces and are trying to avoid using classes. That said, abstract classes my allow us to do all we need to do with these.
I have read a lot of info on all the topics covered by this question as every concept is pretty basic and well covered in online help. But, I have not found anything that I recognize as a direct solution to my specific issue.
Thanks in advance for any help.
I don't know if this is a typo but you have two distinct methods: one that takes no parameter, and another that takes an object, so the compiler requirement is legitimate.
If this is a typo and that you have only one method, say "myFunction()", then I fear VB.Net does not act like C# by simply hiding the base interface and allowing to only implement the derived one.
But you could easily fix this by forwarding:
Namespace ns1
Public Interface IParent
Function myFunction() As Double
End Interface
End Namespace
Namespace ns2
Public Interface IDerived
Inherits ns1.IParent
Function myFunction() As Double
End Interface
End Namespace
Namespace ns3
Public Class Class1
Implements ns2.IDerived
Public Function myFunction() As Double Implements ns2.IDerived.myFunction
Return 42
End Function
Private Function myFunction1() As Double Implements ns1.IParent.myFunction
Return myFunction()
End Function
End Class
End Namespace
Module Module1
Sub Main()
Dim cp As ns1.IParent = New ns3.Class1
cp.myFunction()
Dim cd As ns2.IDerived = New ns3.Class1
cd.myFunction()
End Sub
End Module
EDIT:
So was not a typo, here is the standard (good/best practice?) fix:
Public Class Class1
Implements ns2.IDerived
Public Function myFunction(ByRef obj As Object) As Double Implements ns2.IDerived.myFunction
End Function
Public Function myFunction() As Double Implements ns1.IParent.myFunction
Throw New NotImplementedException("'ns1.IParent.myFunction' has not been implemented because unicorns can't fly!")
End Function
End Class
I don't believe that what you want to accomplish is possible the way you are trying... As I recall when you inherit an Interface any class that implements your derived Interface is actually being told that it must implement both Interfaces rather allowing the options you have in a full class.
So effectively what you have in myClass is:
Namespace ns3
Public Class myClass
Implements ns2.IDerived
Implements ns1.IParent
Public Function myFunction(ByRef obj as Object) As Double Implements ns2.IDerived.myFunction
End Function
End ns3
So inheriting an interface is really just a way to enforce that a class implementing the derived interface must also implement the base interface.
Shell example is below. Basically, I want a client and employee to implement the SSN property from IPerson. However, I want client to have get and set (which isn't an issue), but I want employee to have get only.
Public Interface IPerson
Property SSN As String
End Interface
Public Class Client
Implements IPerson
Public Property SSN As String Implements AELName.IPerson.SSN
Get
Return _SSN
End Get
Set(value As String)
_SSN = value
End Set
End Property
End Class
Public Class Employee
Implements IPerson
Public Readonly Property SSN As String Implements AELName.IPerson.SSN
Get
Return _SSN
End Get
End Property
End Class
Employee generates an error of "'SSN' cannot implement 'SSN' because there is not matching property on interface 'IPerson'". Is there a somewhat simple way to override the SSN implementation for Employee?
You can implement an empty Set - one that doesn't update anything.
Public Class Employee
Implements IPerson
Public Readonly Property SSN As String Implements AELName.IPerson.SSN
Get
Return _SSN
End Get
Set
' Make read only for Employee
End Set
End Property
End Class
I would suggest splitting the interface into IReadablePerson and IReadWritePerson, with the latter inheriting the former. Note that the former interface is not IImmutablePerson, since the latter name would imply to consumers of the class that they should not expect any of its properties ever to change; an object which implements IReadWritePerson would not abide such expectation, but would abide the expectation that the person should be readable.
One slight annoyance with splitting the interface is that it will be necessary for the IReadWritePerson to include the modifier Shadows in the declarations of its read/write properties, and implementers of IReadWritePerson will have to provide both a read-only implementation of IReadablePerson and a read-write implementation of IReadWritePerson. In C#, a public implementation of a read-write property can automatically generate implementations for any like-named read-only, write-only, or read-write properties which are part of any interfaces the class implements, but when explicitly declaring which interface is being implemented, the style of the interface (read-only, write-only, read-write) must precisely match that of the implementation. Annoying.
The annoyance is made worse by the fact that one cannot simply declare IReadableFoo with a read-only property, IWriteOnlyFoo with a write-only property, and have IReadWriteFoo simply inherit both. If an interface implements a read-only property and a write-only property with the same name, neither property will be usable because the compiler will announce that in statements like somevariable = object.someProperty or someObject.someProperty = someVariable, it's "ambiguous" which implementation to use. Not that I can see any ambiguity--I can't see how the first could use anything but a getter, or the latter anything but a setter, but the compiler can't resolve it.
To answer your title question "Can I override an interface property" ... Absolutely. Here's an example of how to do so. You simply add the Overridable keyword to your base concrete implementation. I know that doesn't solve changing the property to ReadOnly, but I figured I'd point out that overriding a base classes concrete implementation of an interface is possible.
Module Module1
Sub Main()
Dim iEntity As IEntity = New MyEntity
iEntity.SetMessage(iEntity)
Console.WriteLine(iEntity.Message)
Console.ReadKey()
End Sub
End Module
Public Interface IEntity
Property Message As String
Sub SetMessage(entity As IEntity)
End Interface
Public Class MyEntity
Inherits BaseEntity
Public Overrides Property Message As String
Get
Return String.Format("{0}.. and overroad.", MyBase.Message)
End Get
Set(value As String)
MyBase.Message = value
End Set
End Property
Public Overrides Sub SetMessage(entity As IEntity)
Me.Message = "I was set from MyEntity."
End Sub
End Class
Public Class BaseEntity
Implements IEntity
Public Overridable Property Message As String Implements IEntity.Message
Public Overridable Sub SetMessage(entity As IEntity) Implements IEntity.SetMessage
Me.Message = "I was set from BaseEntity."
End Sub
End Class
I have a parent class that is also a factory. For example:
Public Class Factory
Public Function clone() as Factory
' Some logic here
' return something
End Function
Public Function all() as List (Of Factory)
' Some logic here
' return something
End Function
End Class
And then an inherited one
Public Class BookFactory
inherits Factory
End Class
I can use inflection in the Factory class to generate the proper extended objects when called by the inherited one. myBookFactory.clone() will then return a BookFactory instance and not only a Factory instance.
The problem: this BookFactory instance will be cast as Factory, since the type of the function is Factory and not BookFactory.
I'd like to do something like
Public Class Factory
Public Function clone() as Me.GetType()
' Some logic here
' return something
End Function
Public Function all() as List (Of Me.GetType())
' Some logic here
' return something
End Function
End Class
So the returned value would be correctly cast and avoid having to do this each time:
Dim myBookFactory2 = DirectCast(myBookFactory1.clone(), myBookFactory1.getType())
How can I do this?
This seems to be a variation on asking for covariant return types. As you have noticed, this is not supported by VB.NET (or C# for that matter). Typically this is asked in the context of overriding virtual methods, where it is still not allowed. There are several alternatives, each with their own pros and cons.
Use a generic template argument to specify the derived class
This is similar to the way IComparable<T> is most commonly implemented.
Public Class Factory(Of T As Factory)
Public Function Clone() As T
'use GetType(T) to determine derived type
End Function
End Class
Public Class BookFactory
Inherits Factory(Of BookFactory)
End Class
Additionally, if you can add a New constraint to the Factory (eg: Factory(Of T {New, Factory(Of T)})) base class, you may be able to avoid using reflection.
However, this does not prevent the accidental (or potentially malicious) mistake of declaring a class like this:
Public Class EvilFactory
Inherits Factory(Of BookFactory)
'hmmm, now clone will be making the wrong type
End Class
Also, this approach makes it impossible to create a list of factories of different types without resorting to another base class below Factory(Of T) or declaring the list as being of object.
Make new methods on the derived classes that return the specific type you want.
Public Class Factory
Public Function Clone() As Factory
'create derived class, but return as base
End Function
End Class
Public Class BookFactory
Inherits Factory
Public Function CloneBooks() As BookFactory
Return CType(Me.Clone(), BookFactory)
End Function
End Class
This allows you to hide the cast for those times when you know you have a BookFactory and want to get another BookFactory. It also lets you treat all factory types polymorphically in the normal inheritance sense. However, if you have an object typed as Factory, you will still get back an object type as Factory.
Reconsider the inheritance relationship
Depending on how these classes are used, it may not make sense to use the inheritance relationship here. If you are only concerned with not retyping code, you may want to look into code generation instead.
You could potentially use generics to make the problem easier, but it won't remove the requirement to cast at some point. For example:
Public Class Factory(Of T)
Public Function clone() As Factory(Of T)
' Some logic here
' return something
End Function
Public Function all() As Collections.Generic.List(Of T)
' Some logic here
' return something
End Function
End Class
Public Class BookFactory
Inherits Factory(Of Book)
End Class
In .net, it's possible to use generics so that a function can accept arguments which support one or more interfaces and derive from a base type, even if there does not exist any single type from which all valid argument types derive. For example, one could say:
Sub Foo(Of T As {IInterface1, IInterface2, SomeBaseType})(Param as T)
and be allowed to pass any derivative of SomeBaseType which implements both IInterface1 and IInterface2. This will work even if SomeBaseType does not support Interface1 and Interface2, and classes which do implement those interfaces don't share any common ancestor that also implements them.
This can be very convenient if one won't need to keep the parameter anywhere after the function has exited. Unfortunately, I can't figure out a way to persist the passed-in parameter in such a way that it can later be passed to a similar function, except perhaps by using Reflection. Is there any nice way of doing that?
The closest I've been able to come up with is to define an interface INest (perhaps not the best name--can anyone improve it?) thus:
Interface INest(Of Out T)
Function Nest() As T
End Interface
And for any interface that will be used in combination with others or with base-class "constraint", define a generic version as illustrated below
Interface IFun1
' Any members of the interface go here, e.g. ...'
Sub DoFun1()
End Interface
Interface IFun1(Of Out T)
' This one does nothing but inherit'
Inherits IFun1, INest(Of T)
End Interface
A class which will support multiple interfaces should declare itself as implementing the generic ones, with itself as the type argument.
Class test123a
Inherits sampleBase
Implements IFun1(Of test123a), IFun2(Of test123a), IFun3(Of test123a)
End Class
If that is done, one can define a function argument or class variable that supports multiple constraints thusly:
Dim SomeField as IFun1(Of IFun2(Of IFun3(Of sampleBase)))
and then assign to it any class derived from sampleBase, which implements those interfaces. SomeField will implement IFun1; SomeField.Nest will implement IFun2; SomeField.Nest.Nest will implement IFun3. Note that there's no requirement that IFun1, IFun2, IFun3, or sampleBase share any common derivation other than the generic interfaces inheriting from INest(Of T). Note also that, no matter how many INest-derived interfaces a class implements, it only needs to define one implementation of INest(Of T).Nest.
Not exactly beautiful, but there are two nice things about it: (1) any concrete class which in fact implements the necessary interfaces can be assigned directly to a field declared as above, without a typecast; (2) while fields which chain the types in a different order are not assignment compatible, they may be typecast to each other.
Is there any better way to store something in such a way that it's "known" to support multiple interfaces and derive from a certain base type? Given that one can write such code in a type-safe manner, it would seem like the .net 2.0 CLR could probably support such a thing quite nicely if compilers offered a little assistance. I'm unaware of any particularly nice approach with present compilers, though.
The best way I can think of is to make an abstract storage and generic implementation of this storage. For example (excuse my VB.NET):
MustInherit Class Storage
Public MustOverride Sub DoSomething()
End Class
Class Storage(Of T As {IInterface1, IInterface2, SomeBaseType})
Inherits Storage
Public Overrides Sub DoSomething()
' do something with Value.
End Sub
Public Value As T
End Class
And usage
Dim S As Storage
Sub Foo(Of T As {IInterface1, IInterface2, SomeBaseType})(ByVal Param As T)
S = New Storage(Of T) With {.Value = Param}
End Sub
Sub UseS()
S.DoSomething();
End Sub
Update: Ok, because we may not be able identify in advance all of the actions:
MustInherit Class Storage
MustOverride ReadOnly Property SomeBaseType As SomeBaseType
MustOverride ReadOnly Property IInterface1 As IInterface1
MustOverride ReadOnly Property IInterface2 As IInterface2
End Class
Class Storage(Of T As {IInterface1, IInterface2, SomeBaseType})
Inherits Storage
Public Value As T
Public Overrides ReadOnly Property IInterface1 As IInterface1
Get
Return Value
End Get
End Property
Public Overrides ReadOnly Property IInterface2 As IInterface2
Get
Return Value
End Get
End Property
Public Overrides ReadOnly Property SomeBaseType As SomeBaseType
Get
Return Value
End Get
End Property
End Class