I know there are a number of post out there on Interfaces and Base classes, but I’m having a hard time getting the correct design pattern understanding.
If I were to write a reporting class, my initial though would be to create an interface with the core properties, methods, etc. that all reports will implement.
For example:
Public Interface IReportSales
Property Sales() As List(Of Sales)
Property ItemTotalSales() As Decimal
End Interface
Public Interface IReportProducts
Property Productss() As List(Of Inventory)
Property ProductsTotal() As Decimal
End Interface
Then I assume I would have a class to implement the interface:
Public Class MyReport
Implements IReportSales
Public Property Sales() As System.Collections.Generic.List(Of Decimal) Implements IReportItem.Sales
Get
Return Sales
End Get
Set(ByVal value As System.Collections.Generic.List(Of Decimal))
Items = value
End Set
End Property
Public Function ItemTotalSales() As Decimal Implements IReport.ItemTotalSales
Dim total As Decimal = 0.0
For Each item In Me.Sales
total = total + item
Next
End Function
End Class
My thought was that it should be an interface because other reports may not use “Items”, this way I can implement the objects that are used for a given report class.
Am I way off? should I have still have just created a base class? My logic behind not creating a base class was that not all report classes may use “Items” so I didn’t want to define them where they are not being used.
To attempt to answer you question, abstract classes are used to provide a common ancestor for related classes. An example of this in the .Net API is
TextWriter. This class provides a common ancestor all various classes whose purpose is to write text in some fashion.Interfaces are more properly used to act as adapters for different objects that don’t belong in the same “family” of objects but have similar capabilities. A good example of this can be seen with the various collections in the .Net API.
For example, the
ListandDictionaryclasses provide the ability for you to manage a collection of objects. They do not share a common ancestor by inheritance, this wouldn’t make sense. In order to allow easy interop between them though, they implement some of the same interfaces.Both classes implement
IEnumerable. This cleanly allows you use objects of either typeListorDictionaryas an operand for anything that requires anIEnumerable. How wonderful!So now in your case in designing new software you want to think about how this would fit into your problem space. If you give these classes a common ancestor via inheritance of an abstract class you have to be sure that all the items that inherit from it are truly of the base type. (A
StreamWriteris aTextWriter, for example). Inappropriate use of class inheritance can make your API very difficult to build and modify in the future.Let’s say you make an abstract class,
ReportBase, for your repots. It may contain a few very generic methods that all reports simply must have. Perhaps it simply specifies the methodRun()You then only have one type of report you want to make so you define a concrete
Reportclass that inherits fromReportBase. Everything is great. Then you find out you need to add several more types of reports,XReport,YReport, andZReportfor sake of example. It doesn’t really matter what they are, but they work differently and have different requirements. All of the reports generate pretty HTML output and everyone is happy.Next week your client says they want
XReportandYReportto be able to output PDF documents as well. Now there are many ways to solve this, but obviously adding anOutputPdfmethod to your abstract class is a poor idea, as some of those reports shouldn’t or can’t support this behavior!Now this is where interfaces could be useful to you. Let’s say you define a few interfaces
IHtmlReportandIPdfReport. Now the report classes that are supposed to support these various output types can implement those interfaces. This will then let you create a function such asCreatePdfReports(IEnumerable<IPdfReport> reports)that can take all reports that implement IPdfReport and do whatever it needs to do with them without caring what the appropriate base type is.Hopefully this helps, I was kind of shooting from the hip here as I’m not familiar with the problem you’re trying to solve.