When I would need to create an interface when designing my application ?

Feb 9, 2010 Posted by Lara Kannan
Question ...
When I would need to create an interface when designing my application ?

Short Answer...
When you want to abstract out what is required from how that requirement is met.

Full Answer...

The somewhat longer answer is to start with some of the premises of writing Clean Code:

  • Each method should be very short and do just one thing

  • Each class should have one easily articulated area of responsibility

  • Classes should know what other classes do but not how.

Let's look at how that might play out with an small example...

You might start off by refactoring into a Note class and a FileManager class like this:

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( "Here I would interact with you and offer you
a writing surface"
);
Console.WriteLine( "Then when you push the right button,
I ask FileManager to "
);
Console.WriteLine("print the file..." );

var fm = new FileManager();
fm.Print(text);
}
}

class FileManager
{
public void Print(string text)
{
Console.WriteLine( "I'm pretending to backup the old version of the file and then " );
Console.WriteLine( " print the text you sent me " );
Console.WriteLine( " printing {0}" , text );
var writer = new StreamWriter( @"c:\temp\HelloWorld.txt", true );
writer.WriteLine( text );
writer.Close();
}
}
}

This console program is stripped of all error checking and all three classes are in one file to keep things simple. The idea is that the NotePad class interacts with the user, obtains a string to print, and then sends it to the FileManager whose job is to see if the file exists, if so make a backup, and then write the user’s text to the file (presumably we’d open a file save dialog rather than just assuming the user wants to write to c:\temp\HelloWorld.txt).

Adding A Second Writer

After creating the above, you realize that there will be times that you will want to write to, e.g., Twitter. You could put in a branching statement:

using System.IO;
using System;

namespace Interfaces
{
class Program
{
static void Main( string[] args )
{
new NotePad().NotePadMainMethod();
}
}

class NotePad
{
private string text = "Hello world";

public void NotePadMainMethod()
{
var dest = "Twitter";
switch ( dest )
{
case "File":
var fm = new FileManager();
fm.Print( text );
break;
case "Twitter":
var tm = new TwitterManager();
tm.Tweet( text );
break;
}
}
}


class FileManager
{
public void Print(string text)
{
// write to file
}
}

class TwitterManager
{
public void Tweet( string text )
{
// write to twitter
}
}
}


Adding An Interface

This begins to get ugly, and more important, the NotePad class is now entirely dependent on both the FileManager class and the TwitterManager class. It is cleaner, easier to maintain, and far easier to test, if we remove those dependencies.

The first step in doing so is to have the NotePad not know which class will take care of writing the message; all it needs to know is that some class that knows how to "Write" will do the work. We accomplish this by creating an interface, Writer that has a Write method.

interface Writer
{
void Write(string whatToWrite);
}

We then have the FileManager and TwitterManager classes implement this interface:

class FileManager : Writer
{
public void Write( string text )
{
// write to a file
}
}

class TwitterManager : Writer
{
public void Write( string text )
{
// write to Twitter stream
}
}

At this point, we return to the NotePad and it can instantiate the class it wants as a Writer:

public void NotePadMainMethod()
{
var w = new TwitterManager();
w.Write( text );
}

That is step 1 in decoupling the NotePad from the other classes; now all it knows is that it has a Writer, which can be one or the other of the streams (or any other class that implements that method) but we’re hard coding which implementing class to use (in this case TwitterManager) in the NotePad class… not great.

Dependency Injection

Dependency Injection is one of those terms you really want to work into your conversation at every conference you attend. It marks you as a cutting edge, in the know kind of geek.

Here’s how it works. You don't want to hard-code the dependency into NotePad because that makes for code that is hard to maintain and hard to test.

What you can do, instead, is “inject” the dependency at run time. You can inject in a number of ways, the most common of which are:

  • Constructor injection

  • Property injection

  • Parameter injection

  • Using a Factory

  • Using an Inversion of Control (IoC) container

(Yes, IoC container may be even cooler than dependency injection. More on IoC below, but not much more)

1. Constructor injection just says that we’ll let the Notepad know which type of writer it is going to use when we create the class:

class NotePad
{
private string text = "Hello world";
private Writer w;
public NotePad( Writer w )
{
this.w = w;
}

public void NotePadMainMethod()
{
w.Write( text );
}
}

Notice that we pass in an instance of Writer, stash it away in a member variable and then NotePadMainMethod just uses it. The actual instance is not created in NotePad, it is created in whomever instantiates the NotePad and “injected” into NotePad through the constructor.

2. Property Injection works the same way, but instead of passing in the writer through the constructor, you set a property,

public Writer MyWriter { get; set; }

public void NotePadMainMethod()
{
MyWriter.Write( text );
}

Now whoever instantiates MyWriter just sets the property and NotePad can take it from there.

3. Parameter Injection, as you can, by now imagine, eschews having a member variable, and just passes the type of writer into the method as a parameter

public void NotePadMainMethod(Writer w)
{
w.Write( text );
}


4 & 5. Factory Pattern and IoC Containers
Please refer in online.

Source : Blog Silverlight.net

Share
Labels: ,

Post a Comment