Tuesday, May 1, 2012

Interfaces

Interfaces are one of the most powerful entities in software development.  Couple an interface with a dictionary and you have a very powerful application with extensibility and maintains the SOLID principle.

You may come to a point where you have to load data from a file.  No big deal so far.  But what if the data can come to you in multiple file formats.  Many developers still to this day would then setup a switch statement and depending on the file extension would then define how the file gets loaded.
Code Snippet
  1. Dim extension As String = IO.Path.GetExtension(filename)
  2.  
  3.         Select Case extension
  4.             Case ".csv"
  5.                 ' Load csv file.
  6.             Case ".txt"
  7.                 ' Load a text file.
  8.             Case ".xls"
  9.                 ' Load a spreadsheet file.
  10.         End Select

This works, but now you have three different subroutines that load a file in a class that is meant to have the data and not load the data.  This violates the single responsibility principle.  So instead we can create a dictionary that will be able to determine what file will get loaded.
Code Snippet
  1.  
  2. Private fileExtensions As Dictionary(Of IFileLoad.FileExtensions, Lazy(Of IFileLoad))

The interface IFileLoad code is below.
Code Snippet
  1. Public Interface IFileLoad
  2.     Enum FileExtensions As Integer
  3.         CSV = 0
  4.         TXT = 1
  5.         XLS = 2
  6.     End Enum
  7.  
  8.     Function ImportFile(filename As String) As List(Of IOrder)
  9. End Interface

Add the dictionary items so that they will load up the correct classes that can implement the IFileLoad interface.  A side note is now if you have to export data then you have a class ready to implement a new export interface.  The single responsibility then becomes input/output of files.
Code Snippet
  1.  
  2. fileExtensions.Add(IFileLoad.FileExtensions.CSV, New Lazy(Of IFileLoad)(Function() New CSVImport))
  3. fileExtensions.Add(IFileLoad.FileExtensions.CSV, New Lazy(Of IFileLoad)(Function() New TXTImport))
  4. fileExtensions.Add(IFileLoad.FileExtensions.CSV, New Lazy(Of IFileLoad)(Function() New XLSImport))

The IOrder interface is then used because it won't matter if the order has additional detail, we just need the basics of an order.  This allows the application to become extensible.
Code Snippet
  1. Public Interface IOrder
  2.     Property OrderID As Integer
  3.     Property OrderNumber As String
  4.     Property OrderType As String
  5.     Property Price As Double
  6. End Interface

Finally, we then get the file extension that will return the list of our orders.
Code Snippet
  1. Dim extension As String = IO.Path.GetExtension(filename)
  2.         Dim importfile As IFileLoad = fileExtensions(extension.TrimStart(".")).Value
  3.         Dim orders As List(Of IOrder) = importfile.ImportFile(filename)

This is so extremely powerful and maintains the single responsibility principle while using dependency inversion.  Two key components of SOLID.

No comments:

Post a Comment