Принцип разделения интерфейса

      Комментарии к записи Принцип разделения интерфейса отключены

В этой теме 0 ответов, 1 участник, последнее обновление  Васильев Владимир Сергеевич 3 нед., 5 дн. назад.

  • Автор
    Сообщения
  • #4032

    Принцип разделения интерфейса звучит так: клиенты не должны зависеть от методов, которые они не используют. Речь идет о базовых типах данных, которые вынуждают своих наследников знать и делать слишком много.

    Предположим, есть базовый интерфейс для некого девайса. Он предоставляет нам возможность осуществлять звонки, и пользоваться телефонной книжкой, и играть в игры, и пользоваться интернетом, и читать книги, и устанавливать будильник. Соответственно, предполагалось, что все классы, реализующие данный интерфейс будут обладать как минимум такой функциональностью. Но вопрос, нужны ли все сразу эти опции всем устройствам. Такое явление имеет своё имя – толстый интерфейс. И он проявляется в непродуманном наполнении функциональными возможностями базового типа, например, класса.

    Вот примерно как может выглядеть чрезмерное напичкивание функционалом базового типа:

    interface IDevice
    {
       void MakeACall(string number);
       string FindContact(string name);
       void CreateNewContact(string number, string name);
       void CreateNewMessage(string text);
       void SendMessage(string to, string text);
       DateTime GetCurrentTime();
       void SetTime(DateTime time);
       void SetAlarmTime(DateTime time);
       void ChooseMelody(string name);
       void ConnectToInternet(string password);
       void UseBrowser(string name);
       void DownloadProgram(string name);
       void UseOnlineService(string name);
       void FindBook(string name);
       void OpenBook(string name, int page);
       void NextPage(string book, int currentPage);
       void PreviousPage(string book, int currentPage);
       void CreateBookmark(string book, int page);

    Не всякое устройство для чтения должно осуществлять звонки и скачивать дополнительные программы, и быть будильником, не каждый телефон должен быть читалкой и уметь качать программы из интернета. И так далее. Очевидно, что подход к разработке интерфейса должен был быть более тонким, продуманным.

    Если попробовать разделить на логические группы всю функциональность этого интерфейса, то получится более красивая картинка:

    interface ICallingDevice
    {
       void MakeACall(string number);
       string FindContact(string name);
       void CreateNewContact(string number, string name);
       void CreateNewMessage(string text);
       void SendMessage(string to, string text);
    }
    
    interface IAlarmClock
    {
       DateTime GetCurrentTime();
       void SetTime(DateTime time);
       void SetAlarmTime(DateTime time);
       void ChooseMelody(string name);
    }
    
    interface INetworkDevice
    {
       void ConnectToInternet(string password);
       void UseBrowser(string name);
       void DownloadProgram(string name);
       void UseOnlineService(string name);
    }
    interface IReaderDevice
    {
       void FindBook(string name);
       void OpenBook(string name, int page);
       void NextPage(string book, int currentPage);
       void PreviousPage(string book, int currentPage);
       void CreateBookmark(string book, int page);
    }

    Интерфейс ICallingDevice инкапсулирует логику для осуществления звонков, интерфейс IAlarmClock — отвечает за логику устройства, которая касается использование часов и будильника, интерфейс INetworkDevice — отвечает за поведение сетевого устройства, интерфейс IReaderDevice — позволит наследникам определить функционал для устройств чтения (электронной книги).

    Все опции чётко разграничены по логическим направлениям, и в дальнейшем будет проще наделить классы – наследники только той функциональностью, которая им необходима, не включая ничего лишнего. Соответственно, второй подход как раз демонстрирует грамотное использование принципа разделения интерфейса.

Для ответа в этой теме необходимо авторизоваться.