Интерфейсы - это форма абстракции.Когда вы определяете интерфейс, вы определяете контракт, которому должно соответствовать все, что претендует на реализацию этого интерфейса.Исходя из этого, вы можете заменить любую реализацию любой другой реализацией, поскольку все они придерживаются этого контракта.
Хотя существует множество причин, по которым вы хотели бы этого, одна из основных - это тестируемость.Допустим, у вас есть класс, который зависит от конкретного поставщика базы данных:
public class FooService
{
private readonly SqlConnection _db;
public FooService(SqlConnection db)
{
_db = db;
}
}
Из-за жесткой зависимости SqlConnection
здесь вы можете использовать только этого конкретного поставщика.При модульном тестировании этой службы вам необходимо будет подключиться к реальному экземпляру SQL Server, поскольку нет способа абстрагировать эту зависимость.Затем у вас есть дополнительная переменная, поскольку ваш тест может не пройти из-за реальной проблемы с вашим сервисом или просто из-за проблем с подключением к SQL Server.Вы никогда не узнаете.
Теперь представьте, что вы сделали это вместо этого:
public class FooService
{
private readonly IDbConnection _db;
public FooService(IDbConnection db)
{
_db = db;
}
}
Теперь вы можете передать все, что реализует этот интерфейс.Вы можете использовать SqlConnection
, OracleConnection
и т. Д. Или даже полностью смоделированный IDbConnection
, который хранит данные в памяти и возвращает готовые ответы.