65.9K
CodeProject is changing. Read more.
Home

Using Interfaces to Abstract your Modules

starIconstarIconstarIconstarIconemptyStarIcon

4.00/5 (1 vote)

Feb 9, 2010

CPOL

3 min read

viewsIcon

5249

Introduction...

Introduction

Careful application of abstraction can provide a much cleaner approach to solving many of the structural issues we face in our coding every day. While the combination of words like 'abstraction' and 'cleaner' may seem like opposite concepts, once you get used to thinking in terms of abstracting 'similar but slightly different' modules using a single abstracted interface, it soon becomes second nature and a very powerful approach. By abstracting your various similar modules using a common interface, you empower yourself to write a SINGLE set of code that can operate with all of the various modules in an identical manner. While this sounds simple enough, in practice we all tend to see a lot of cut and paste approaches to this common problem, where you find variations of logic within the same blocks of code using many case like statements, each of which takes care of a slightly different aspect of your various module's needs. This type of code is a prime contributor to increasing pasta levels and global warming.

Background

Possible scenario's might include:
  • Creating a program that must operate using several different databases, depending on customer needs.
  • Creating a transmission program that can utilize several different protocols, or even flat-file output.
  • Creating a Payment managment program that must interface with various Payment Processors. 
  • Creating a 'plug-in' architecture for a new program where additional modules can be added at run-time to do new things.
  • and hundreds more..
I'm sure if you think back through your experiences, you will find some examples of where you see entirely seperate programs being developed, that all do basically the very same thing, but they all operate using perhaps a different database, or perhaps a different set of input files, or output methods. It actually occurs quite often, and forces developers to make the very same fixes or enhancements in multiple code-bases rather than just one. For our example, we're going to show the basic structure of what I call a message transmitter pump. This beast basically takes a message and sends it out using a protocol chosen by the user. The main program and TransmitPump class deal strictly with an interface and have no knowledge of the underlying workings of any specific transmitter, which is the point of the exercize.

Using the Code

In the example below, you can see a common interface (ITransmit) which is supported by any transmitter we choose to implement. The code in Main() or in the TransmitPump class has no knowledge of the inner workings of any specific transmitter module, which means we have effectively abstracted those details away from the main logic of our program.
		
	// All transmission modules would support this interface.
	public interface ITransmit
	{
		// Transmit method.
		void Transmit(SomeMessageType message);
	}
	// Note, this is abstracted, so you could implement a variety of types of 
	// transmitters.  Named pipes, POST, etc..
	public class TCPIP_Transmitter : ITransmit
	{
		// Implement Transmit() method.
	}
	
	// Here's another type.  Details of using FTP for tranmitting would be 
	// burried in here and the reset of the program would not need to know 
	// about it.
	public class FTP_Transmitter : ITransmit
	{
		// Implement Transmit() method.
	}

	public class TransmitPump
	{
	    // Can make into a property.
		private ITransmit m_Transmitter = null;	
		public TransmitPump(ITransmit Transmitter)
		{
			m_Transmitter = Transmitter;
		}
		public void SendMessage(SomeMessageType Message)
		{
			if (m_Transmitter != null)
			    m_Transmitter.Transmit(Message);
		}
	}
	Main()
	{
		// We've decided to use a TCPIP Transmitter this time.  
		TransmitPump tp = new TransmitPump(new TCPIP_Transmitter());
		
		// Regardless of which type of transmitter you use, the interface 
		// to it is always the same.  
		SomeMessageType message = new SomeMessageType(....);
		tp.SendMessage(message);
	}

Points of Interest

This is a very simple example, but it demonstrates the pattern effectively. For simple programs this may seem like overkill, but don't be fooled: simple programs have a tendency to grow over time. As your needs and code get more complex (and it always does), using this pattern always tends to yield far better returns in terms of structural simplicity in your upper-level code than taking a hard-coded "case statement" type of approach to dealing with different behaviors.