Daj Się Poznać SOLID

SOLID #4 – ZASADA SEGREGACJI INTERFEJSÓW

W poprzednim wpisie opisałem trzecią zasadę w mnemoniku SOLID czyli zasadę podstawienia Liskov. Kontynuując, dzisiaj przyszedł czas na drugą czwartą literę tego skrótu czyli I, a wraz z nią zasadę segregacji interfejsów (ang. Interface segregarion principle).

CO TO JEST ZASADA SEGREGACJI INTERFEJSÓW

Interfejsy powinny być małe i konkretne aby klasy nie implementowały metod, których nie potrzebują.

Omawiana tutaj reguła idealnie wpasowuje się we wcześniej poznane zasady mnemonika SOLID.  Skłania ona do bycia zwięzłym w definiowaniu interfejsów. Powinny one zawierać minimalną liczbę deklaracji metod, a same metody w jednym interfejsie powinny być ze sobą ściśle powiązane. Postępowanie zgodne z tą regułą usprawni wiedza o Zasadzie pojedynczej odpowiedzialności.

Dodatkowym elementem jest świadomość o wielodziedziczeniu interfejsów języka C#. Zachodzi ono zarówno w odniesieniu do klas jak i interfejsów. Oznacza to tyle, że lepiej tworzyć mniejsze kontrakty danych, niż jeden ogromny (tzw. fat), który zmusza programistę do każdorazowego dostarczenia definicji wszystkich metod.

PRZYKŁAD

Aby jak najlepiej pokazać na czym polega ta zasada posłużę się przykładem, który w późniejszym etapie zostanie zaimplementowany w mojej aplikacji konkursowej. Załóżmy, że posiadam interfejs, który daje dwie możliwości generowania diety do pdf, bezpośredni druk oraz zapis do bazy danych.

public interface IBaseFeatures

{

     void SaveToDatabase();

     void Print();

     void PrintToPdf();

}


public class Diet : IBaseFeatures

{

   public void SaveToDatabase()

   {

      //implementation

   } 


   public void Print()

   {

      throw new NotImplementedException();

   } 


   public void PrintToPdf()

   {

      throw new NotImplementedException();

   }

}

 

Powyższy kod jest błędny, ponieważ nie dość, że zmuszeni jesteśmy zaimplementować metody, które nie są konieczne w danej klasie to dodatkowo metody zawierające throw new NotImplementedException() łamią omawianą poprzednio Zasadę podstawienia Liskov.

Aby powyższe problemy nie występowały zamiast głównego interfejsu IBaseFeatures możemy utworzyć kilka mniejszych interfejsów.

public interface ISaveToDatabase

{

   void SaveToDatabase();

}


public interface IPrint

{

   void Print();

}


public interface IPrintToPdf

{

   void PrintToPdf();

}

 

Ponieważ w C# występuje wielodziedziczenie interfejsów nie ma problemu, aby w dowolnej klasie zaimplementować np. dwie z powyższych funkcjonalności:

public class Diet : ISaveToDatabase, IPrintToPdf

{

   public void SaveToDatabase()

   {

      //implementation

   }

   public void PrintToPdf()

   {

      //implementation

   }

}

Dzięki podzieleniu interfejsu na mniejsze, utrzymujemy porządek w interfejsie polimorficznym typu. Dzięki temu typy pochodne nie są związane kontraktami, które nie są im potrzebne.

PODSUMOWANIE

Zasada segregacji interfejsów wymusza budowanie wielu krótkich i zwięzłych interfejsów, zamiast rozbudowanych gigantów, które dostarczają wielu problemów i niejasności, gdy jesteśmy do ich wielokrotnego użycia.

Niewątpliwie w poprawnym definiowaniu zawartości interfejsu pomaga wejście w perspektywę klienta i próba określenia jego oczekiwań oraz wymagań.

DO NASTĘPNEGO!

Dodaj komentarz