Интерфейсы в C# используются для достижения следующих целей:
Определение контракта: Интерфейс определяет набор членов (методы, свойства, события, индексаторы), которые класс или структура, реализующие этот интерфейс, обязаны реализовать. Это обеспечивает единообразие в поведении различных типов.
// Определение интерфейса
public interface IDrawable
{
void Draw();
int LineThickness { get; set; }
}
// Класс, реализующий интерфейс
public class Circle : IDrawable
{
public int LineThickness { get; set; }
public void Draw()
{
// Логика рисования круга
}
}
Полиморфизм: Использование интерфейсов позволяет работать с объектами разных типов через общий интерфейсный тип. Это достигается за счет того, что любая ссылка на объект, реализующий интерфейс, может быть приведена к типу этого интерфейса.
// Метод, работающий с любым объектом, реализующим IDrawable
public void Render(IDrawable item)
{
item.Draw(); // Вызывается конкретная реализация метода Draw
}
// Использование:
IDrawable circle = new Circle();
Render(circle); // Будет вызвана реализация Draw() из класса Circle
Multiple Inheritance (множественное наследование): C# не поддерживает множественное наследование классов, но позволяет классу или структуре реализовать несколько интерфейсов. Это позволяет типу иметь поведение, определенное в разных "контрактах".
public interface ISaveable
{
void Save();
}
public interface ILoadable
{
void Load();
}
// Класс, реализующий несколько интерфейсов
public class ConfigurationManager : ISaveable, ILoadable
{
public void Save()
{
// Логика сохранения
}
public void Load()
{
// Логика загрузки
}
}
Слабая связанность (Decoupling): Использование интерфейсов позволяет снизить зависимость между компонентами. Вместо того чтобы зависеть от конкретного класса, компонент может зависеть от интерфейса. Это облегчает замену реализаций и тестирование.
public interface ILogger
{
void LogMessage(string message);
}
public class FileLogger : ILogger
{
public void LogMessage(string message)
{
// Логика записи в файл
}
}
public class DatabaseLogger : ILogger
{
{
// Логика записи в базу данных
}
}
public class ProcessingEngine
{
private readonly ILogger _logger;
// Зависимость от интерфейса, а не от конкретной реализации
public ProcessingEngine(ILogger logger)
{
_logger = logger;
}
public void ProcessData()
{
// ...
_logger.LogMessage("Данные обработаны.");
}
}
Расширяемость: Интерфейсы позволяют легко добавлять новые реализации существующего поведения без изменения кода, который использует этот интерфейс.
Документация и самодокументирование: Хорошо названный интерфейс с комментариями к своим членам служит формой документации, описывающей, какое поведение ожидается от объектов, реализующих этот интерфейс.