I understand that an interface in .Net defines a contract between the interface a开发者_JS百科nd a class that inherits it. Having just gotten done working on a project that made heavy use of an interface for the Data Access Layer, it got me thinking . . . whats the big deal? When I had to add a new method to the DAL, I had to create the method signature in the interface along with adding it to the class that inherited the interface, and of course the method to the DAL, thus creating "extra work". Whats the big deal about interfaces and why would I want to create extra work for myself?
What's the big deal about interfaces?
Once you define the contract, you can swap out implementations without worrying about breaking the rest of your code.
Consider the situation where you have poor performing code that is making use of a List<T>
in .NET. If you use the hard implementation of List<T>
, there's a good chance you're going to break more code by changing the implementation.
If you were using IList<T>
or IEnumerable<T>
you would be able to swap List<T>
for LinkedList<T>
(or anything implementing your chosen interface) and fix the issue in one spot rather than having to touch all of your code.
In the end...it's about about Polymorphism.
The big deal IMO is that interfaces are not tied to a specific inheritance hierarchy as classes are and thus they are much more flexible than classes for implementing abstract interfaces. By using interfaces instead of concrete classes you have a much more loosely coupled system. It is easy to change the implementation: Just supply any other class that implement the required interface.
If you had two classes, two different Data Access Layer classes with different implementations (maybe SQL Server and CouchDB), then having a standard interface (that they both implement) would mean that you have a standard way of interacting with those classes.
You would be able to "hot swap" the different data classes and not have to know the specific underlying implementation.
One reason to use Interfaces is to create a loose coupling between your classes.
If for example you pass an interface in a class constructor, instead of an actual class, you'll allow for a looser coupling. As anyone can inherit from the interface and implement their own implementation.
foreach (object obj in myArray)
{
// distroy all IDisposable objects
if (obj is IDisposable)
(obj as IDisposable).Dispose();
// ends initialization of all ISupportInitialize objects
else if (obj is ISupportInitialize)
(obj as ISupportInitialize).EndInit();
}
So, if some different objects implements the same interface, that interface guarantees that each of have some common methods, described in this interface.
This is very useful in collection of objects. You know that all Animals(human inclusive) can Eat. So you know that if in a car you have animals, each of them could Eat, Human, Mouse or Zebra...
So Interface IEatable :)...
When I was in school, I did not get the beauty of interfaces or even iterators because the problem we tried to solve could have been done in 1/2 amount of code without using abstractions.
In general, software patterns arise out of real need by the industry. I suppose interface was considered almost a pattern at some point.
School projects are limited in what they can teach you due to time limitations.
If you were to change the way your data is stored, you'd just need to create a new class that implements your DAL interface and it will be immediately usable by your application. You won't need to hunt down all the usage instances in your application(s) and replace the old class with the new.
You could also, for example, then use IoC (with the help of Castle Windsor or other libraries) to plug in a particular data access flavour through configuration without having to re-compile your application.
In your example, where you only have one class that implements the interface, you aren't seeing the benefits. If you had 10 classes that all implement that interface you'd instantly see the advantage.
If you have a collection of IFoo, you can stick any class that implements IFoo into that collection and call the same Bar() method on every one of those objects. The implementation of Bar() could be drastically different within each class that implemented it.
In simple terms, an interface is used to provide a clean point of separation between two components. Rather than designing a component to work against a single type (such as List<T>
), you can design to work against an interface (IList<T>
) and be able to work with any object implementing the interface.
This separation is very useful when you start to work with the ideas of Dependency Injection and mocking for testing.
A better way to think about an interface is as a contract between an object (or service) and the user of that service. In your issue with your DAL, the real value of the interface is to be able to replace the class that implements the interface with a different implementation that also implements the interface. So say your DAL implementation is specific to SQL Server, but now you need MySQL support. You write another impl of the interface that talks to MySQL, plug that in, and the code using the DAL doesn't need to change. The advantage is to the client code, not the implementation.
It's also helpful in testing, allowing you to plug in fake or mock implementations of the interface that simulate the desired behavior when executing tests.
I can make my code more testable by using interfaces.
If I have a ManagerClass
public class PersonManager
{
public PersonManager(IPersonRepository repository)
{
this.Repository = repository;
}
private IPersonRepository Repository{get;set;}
public Person ChangeUsername(string username)
{
Person person = this.Repository.GetByUsername(username);
person.Username = username;
this.Repository.Save(person);
return person;
}
}
The release code will use a repository object which will call a database but for my unit test I want to isolate the dependancy on the database so I can create a mock repository which implements my interface:
public class MockPersonRepository : IPersonRepository
{
public Person GetByUsername(string username)
{
return new Person();
}
public void Save()
{}
}
And when I write my unit test I can pass in the mock:
[Test]
public void ChangeUserName_NewUsername_ExpectUpdateUsername()
{
//Arrange
var manager = new PersonManager(new MockPersonManager());
//Act
Person person = manager.ChangeUsername("bob");
//Assert
Assert(AreEqual("bob", person.Username);
}
I've now manager to test that my ChangeUsername method has updated the username whilst not talking to the database
精彩评论