This is a follow-up to Jesse Liberty’s Answering A C# Question blog post which compares two equivalent code examples to illustrate the value of interfaces:
- No interface example
- Interface with Dependency Injection (DI) example
Both examples use fictitious Notepad functionality with File and Twitter capability.
Example #1 does not use an interface and the line of code (LOC) count is 49.
Example #2 uses a Writer interface with Parameter Dependency Injection. The Notepad’s dependent objects (e.g., FileManager and TwitterManager) are passed as parameters (aka injected) to the worker method. In this case, the LOC count is 57.
It’s interesting to note that the interface example has slightly more code. The big win is less coupling which is much easier to maintain and more testable. I’ll have more about the testability in a future post.
Example 1 – No Interface
using System.IO;
using System;
namespace Interfaces
{
class Program
{
static void Main( string[] args )
{
var np = new NotePad();
np.NotePadMainMethod();
}
}
class NotePad
{
private string text = "Hello world";
public void NotePadMainMethod()
{
Console.WriteLine("Notepad interacts with user.");
Console.WriteLine("Provides text writing surface.");
Console.WriteLine("User pushes a print button.");
Console.WriteLine("Notepad responds by asking ");
Console.WriteLine("FileManager to print file...");
Console.WriteLine("");
var fm = new FileManager();
fm.Print(text);
var tm = new TwitterManager();
tm.Tweet(text);
}
}
class FileManager
{
public void Print(string text)
{
Console.WriteLine("Pretends to backup old version file." );
Console.WriteLine("Then prints text sent to me." );
Console.WriteLine("printing {0}" , text );
var writer = new StreamWriter( @"HelloWorld.txt", true );
writer.WriteLine( text );
writer.Close();
}
}
class TwitterManager
{
public void Tweet( string text )
{
// write to twitter
Console.WriteLine("TwitterManager: " + text);
}
}
}
Example 2 – Writer Interface with Parameter Dependency Injection
using System.IO; using System; namespace Interfaces { class Program { static void Main( string[] args ) { var np = new NotePad(); var fm = new FileManager(); var tm = new TwitterManager(); np.NotePadMainMethod(fm); // parameter injection np.NotePadMainMethod(tm); // parameter injection } } class NotePad { private string text = "Hello world"; public void NotePadMainMethod(Writer w) { Console.WriteLine("Notepad interacts with user."); Console.WriteLine("Provides text writing surface."); Console.WriteLine("User pushes a print button."); Console.WriteLine("Notepad responds by asking "); Console.WriteLine("FileManager to print file..."); Console.WriteLine(""); w.Write(text); } } // Writer Interface interface Writer { void Write(string whatToWrite); } class FileManager : Writer // Inherits Writer Interface { // Implements Write Interface Method public void Write(string text) { // write to a file Console.WriteLine("FileManager: " + text); } public void Print(string text) { Console.WriteLine("Pretends to backup old version file." ); Console.WriteLine("Then prints text sent to me." ); Console.WriteLine("printing {0}" , text ); var writer = new StreamWriter(@"HelloWorld.txt", true); writer.WriteLine(text); writer.Close(); } } class TwitterManager : Writer // Inherits Writer Interface { // Implements Write Interface Method public void Write( string text ) { // write to Twitter stream Console.WriteLine("TwitterManager: " + text); } } }