C#,  Programowanie

Nie dziedzicz tego, czyli modyfikator sealed w języku C#

Głównym fundamentem języków zorientowanych obiektowo jest dziedziczenie. Pozwala ono na zachowanie pewnych właściwości rodzica, tych które są publiczne (ang. public) oraz chronione (ang. protected). Dzięki temu programista tworzący podklasę, nie musi za każdym razem tworzyć wspólnych właściwości i innych elementów. Co jednak, jeżeli uważamy, że po naszej klasie inna klasa nie powinna już więcej dziedziczyć? Że to nasza klasa osiąga największą szczegółowość, a tworzenie po niej klasy pochodnej oznacza, że ktoś tutaj nie zrozumiał naszego punktu widzenia?

Na ratunek przychodzi nam modyfikator sealed. Jest to słowo kluczowe wstawiane w definicji naszej klasy przed słówkiem class. Oznacza to, że żadna inna klasa nie może dziedziczyć po klasie sealed. Swoją drogą sealed tłumaczony z angielskiego oznacza zapieczętowany, co idealnie pasuje do sytuacji.

Spójrzcie teraz na przykład poniżej. Co się stanie, gdy spróbujemy taką klasę odziedziczyć.

sealed class Detective
{
   public string Name { get; set; }
   public int Age { get; set; }
   public bool Gender { get; set; }
}

Stworzyłem tutaj klasę detektywa, który ma kilka podstawowych właściwości. Ma ona w sobie zastosowany modyfikator sealed. Teraz klasa młodszego detektywa, która będzie po niej dziedziczyć:

class YoungerDetective : Detective
{
   public int Grade { get; set; }
}

Już przed uruchomieniem aplikacji Visual Studio podkreśla nam na czerwono klasę YoungerDetective. Gdy ją spróbujemy uruchomić dostaniemy błąd:

 

Zastosowanie

Początkowo może wydawać się głupie, dlaczego taki operator w ogóle istnieje. Przecież każdy sobie może “nie dziedziczyć” klasy, bez żadnego modyfikatora sealed. Owszem, może. Ale należy zwrócić uwagę, że systemy są odpowiednio projektowane i nie każdy zna całą architekturę systemu. Pisałem już o tym trochę wyżej, ale jeżeli zaistnieje sytuacja, że ktoś  stworzy klasę o najniższej szczegółowości i ma ona być już na najniższym poziomie hierarchii dziedziczenia, dodanie słowa sealed właśnie to oznacza. Inny programista lub autor w przyszłości będzie tego świadomy, a jak będzie chciał coś zmienić to zastanowi się czy ma to sens i najwyżej usunie modyfikator z klasy wyżej.

 

Drugi przykład

Postaram się teraz opisać przykład, w którym zastosowanie tego modyfikatora miałoby sens. Bo przecież powyżej, młodszy detektyw powinien dziedziczyć po starszym detektywie, a przykład miał tylko pokazać, jak się korzysta z sealed.

Dość dawno temu powstała gra, która cieszy się ogromną popularnością do dnia dzisiejszego. Mowa tutaj o grze Heroes of Might and Magic. W wielu odsłonach tej serii, możliwe było tworzenie jednostek, a następnie ich ulepszanie. Ulepszać dało się tylko do następnego poziomu. Przykładowo jednostkę anioła można było ulepszyć do jednostki archanioła, a jednostkę łucznika, do jednostki kusznika.

Mając to na uwadze, skonstruowałem diagram zależności pomiędzy klasami:

Każda klasa w języku C# dziedziczy po klasie object. Następnie tworzymy klasę Jednostka, która ma w sobie elementy dostępne dla każdej jednostki, takie jak ruch czy zdrowie. Dalej wojownik, bo nasza jednostka walczy w zwarciu. Dalej dochodzimy już do klasy naszej podstawowej jednostki anioła. Ma on w sobie parę kolejnych właściwości, np. możliwość latania. Następnie to wszystko dziedziczy klasa archaniołów. Jest to klasa ostatnia, po niej nie będzie już niczego nowego. Warto tutaj zastosować operator sealed, żeby nikt więcej po niej nie dziedziczył.

Jednak projekt zawsze może ulec zmianie. A co jak w nowej części Heroesów jednostki będzie można aktualizować na trzeci poziom, a my poblokowaliśmy je na poziomie drugim?

Zablokowaliśmy rozwój aplikacji, ale przecież zrobiliśmy to ze względu na kluczowe założenia. Teraz, gdy one się zmieniły musimy wrócić do klas i usunąć z nich użyty modyfikator. Oczywiście ten przykład nadal jest jedynie przykładowy, a jego celem jest to abyś lepiej poznał ten mechanizm.

 

Podsumowanie

Sealed tak jak interfejsy, tworzy kontrakt z programistą. Dzięki niemu wiemy, że nie możemy dziedziczyć po danej klasie, więc w zasadzie tylko się ograniczamy. Ale jest to zaplanowane i świadome ograniczenie. Bez powodu nie powinniśmy używać tego modyfikatora. Operator sealed nie jest często stosowany, ale warto wiedzieć, że coś takiego istnieje.

Social media & sharing icons powered by UltimatelySocial