Скажем, например, у вас есть два класса: Book
и Newspaper
. Вы можете прочитать каждый из них, но для них двоих не имеет смысла наследовать от общего суперкласса. Таким образом, они оба будут реализовывать интерфейс IReadable
:
public interface IReadable
{
public void Read();
}
Теперь предположим, что вы пишете приложение, которое будет читать книги и газеты для пользователя. Пользователь может выбрать книгу или газету из списка, и этот элемент будет прочитан пользователю.
Метод в вашем приложении, который читает пользователю, примет это Book
или Newspaper
в качестве параметра. Это может выглядеть так в коде:
public static void ReadItem(IReadable item)
{
item.Read();
}
Поскольку параметром является IReadable
, мы знаем, что у объекта есть метод Read()
, поэтому мы вызываем его, чтобы прочитать его пользователю. Не имеет значения, является ли это Book
, Newspaper
или чем-то еще, что реализует IReadable
. Отдельные классы реализуют в точности то, как каждый элемент будет читаться с помощью метода Read()
, поскольку он, скорее всего, будет отличаться для разных классов.
Book
Read()
может выглядеть так:
public void Read()
{
this.Open();
this.TurnToPage(1);
while(!this.AtLastPage)
{
ReadText(this.CurrentPage.Text);
this.TurnPage();
}
this.Close();
}
Newspaper
s Read()
скорее всего будет немного другим:
public void Read()
{
while(!this.OnBackPage)
{
foreach(Article article in this.CurrentPage.Articles)
{
ReadText(article.Text);
}
}
}
Дело в том, что объект, содержащийся в переменной, являющейся типом интерфейса, гарантированно имеет определенный набор методов, даже если возможные классы объекта не связаны каким-либо другим образом. Это позволяет вам писать код, который будет применяться к различным классам, которые имеют общие операции, которые могут быть выполнены над ними.