Интерфейс определяет контракт.Это обещание, что объект будет вести себя определенным образом.Прежде чем изучать интерфейсы, вы склонны думать об объектах в конкретных терминах.Например, предположим, что у нас есть список продуктов:
List<string> products = new List<string>() { "desktop", "laptop", "server" };
И у нас есть метод, который распечатывает наши продукты:
void PrintProducts(List<string> products)
{
foreach (string product in products)
{
Console.WriteLine(product);
}
}
Наш метод связан с конкретным типомСписок.Это должно быть хотя?В C # существует множество различных типов коллекций: списки, массивы, ReadOnlyCollection и т. Д. Все, что вам действительно нужно сделать, - это просмотреть их.В списке есть много методов, которых нет в массиве, но здесь вы не используете ни один из них.К счастью, все они реализуют интерфейс IEnumerable.Это означает, что все они «связаны контрактом», чтобы иметь возможность быть перечисленными.
Изменение метода следующим образом:
void PrintProducts(IEnumerable<string> products)
{
foreach (string product in products)
{
Console.WriteLine(product);
}
}
означает, что теперь вы можете передавать массив, или список, или какой-то уникальный контейнер, который вы сами создаете.
Другой пример. Предположим, у вас есть хранилище данных:
public class DatabaseRepository
{
public void AddProduct(Product product)
{
// connect to the database
// add the product
}
}
И у вас есть класс, которому нужна эта база данных:
public class ProductManager
{
DatabaseRepository _repository;
public ProductManager(DatabaseRepository repository)
{
_repository= repository;
}
}
К сожалению, этот класспривязан к вашей базе данных.Что если вы решите перейти на хранение в виде XML-файла или на хранение в каком-либо облачном хранилище ключей-значений.Вам придется изменить ваш ProductManager, который сложен и подвержен ошибкам.Предположим, что вместо этого мы определили интерфейс:
public interface IRepository {
void AddProduct(Product product);
}
Изменение нашего класса ProductManager для использования этого интерфейса вместо этого:
public class ProductManager
{
IRepository _repository;
public ProductManager(IRepository repository)
{
_repository= repository;
}
}
означает, что независимо от того, какой это тип хранилища, мы знаемвсегда будет метод AddProduct (Товарный продукт).Теперь мы можем создать наш XML-репозиторий:
public class XMLRepository : IRepository
{
public void AddProduct(Product product)
{
// write to an XML file
}
}
Теперь мы можем свободно передавать либо репозиторий:
ProductManager manager = new ProductManager(new DatabaseRepository())
или
ProductManager manager = new ProductManager(new XMLRepository())
и наш ProductManagerведет себя точно так же.Он совершенно не знает, что это за конкретный тип.
Это становится очень полезным, когда вы вступаете в юнит-тестирование.Инверсия управления - это то, о чем вы захотите прочитать, когда получите четкое представление о том, как работают интерфейсы.