Online Book Reader

Home Category

Programming Microsoft ASP.NET 4 - Dino Esposito [298]

By Root 5313 0
even represent a constraint and limit further necessary improvements!

The natural solution is to use slimmer interfaces. The IDoor interface should be split into two smaller and much more specific interfaces—say IDoor and ITimedDoor:

public interface IDoor

{

void Lock();

void Unlock();

Boolean IsDoorOpen { get; }

}

public interface ITimedDoor

{

Int32 OpenTimeout { get; set; }

event EventHandler DoorOpenForTooLong;

}

Now if you need to create RegularDoor and TimedDoor classes, you proceed as shown here:

public class RegularDoor : IDoor

{

...

}

public class TimedDoor : IDoor, ITimedDoor

{

...

}

Unlike classes, interfaces can be easily summed up; so there’s really no reason to have fat interfaces any more.

The Dependency Inversion Principle


I consider Dependency Inversion to be the most important of the five SOLID principles. You don’t need it in every class and method that you write, but if you miss it where you need it, well, you’re in serious trouble. Take a look at Figure 13-1.

Figure 13-1. Hard to change blocks in software architecture.

I’m not sure the idea behind this figure is completely original, and I don’t even know if there’s anybody I should thank for that. For sure, I remember having seen it somewhere, likely at some software conference somewhere in the world. Then I simply revised the idea and made it mine.

So you have built the architecture of your system by simply composing parts. What if, at some point during development, you need to replace or significantly modify one of the building blocks? As the graphics attempts to show, it might be hard to change some of the building blocks that form the skeleton of the system. Dependency inversion is simply aimed at making this difficult task simpler and less expensive.

The principle says that every high-level module should always depend on abstractions of lower level modules. This is just a reformulation of the concept of interface-based programming.

Dependency Inversion Canonical Example


The idea behind Dependency Inversion doesn’t need a complex scenario to be effectively illustrated. Just imagine a method that reads bytes from a stream and writes them out to some buffer:

void Copy()

{

Byte byte;

while(byte = ReadFromStream())

WriteToBuffer(byte);

}

The pseudocode just shown depends on two lower level modules: the reader and writer. According to the principle, we should then abstract the dependencies to interfaces—say, IReader and IWriter. The method can be rewritten as follows:

void Copy()

{

Byte byte;

IReader reader;

IWriter writer;

while(byte = reader.Read())

writer.Write(byte);

}

Who really does provide instances of the reader and writer modules? That’s the principle, or the general law; to actually solve the issue, you need some further specification. In other words, you need a pattern.

The first pattern used to apply the Dependency Inversion principle is Service Locator pattern, which can be summarized as follows:

void Copy()

{

Byte byte;

var reader = ServiceLocator.GetService();

var writer = ServiceLocator.GetService();

while(byte = reader.Read())

writer.Write(byte);

}

You use a centralized component that locates and returns an instance to use whenever the specified abstraction is requested. The service locator operates while embedded in the code that it serves. You can say that it looks for services, but it is not a service itself. Most of the time, you use this pattern when you have some legacy code that you need to make easier to extend that is hard to redesign in a different way—for example, in a way that uses dependency injection.

A better alternative is to use Dependency Injection (or inversion of control). The resulting code looks like this:

void Copy(IReader reader, IWriter writer)

{

Byte byte;

while(byte = reader.Read())

writer.Write(byte);

}

The list of dependencies is now explicit from the signature of the method and doesn’t require you to go down the line to pinpoint calls to a service locator component. In addition, the burden of creating

Return Main Page Previous Page Next Page

®Online Book Reader