Fajne rzeczy w Scali: klasy przypadkówKiedy jako programista Javy po raz pierwszy ujrzałam kod napisany w Scali, miałam spore problemy ze zrozumieniem, czym różnią się od siebie poszczególne byty:
class
(klasa)case class
(klasa przypadków)trait
(cecha)object
(obiekt)- instancje klas (bo “obiekt” w Scali to wcale nie jest instancja!).
Poniżej ściąga dla zainteresowanych i dla przyszłej mnie 🙂
Klasa
Klasa (class
) jak w przypadku większości obiektowych języków programowania, to szablon, na podstawie którego można tworzyć ukonkretnione instancje. Zawiera pola i metody. Ponieważ Scala jest językiem funkcyjnym, dobrym zwyczajem jest tworzenie klas niemodyfikowalnych.
Klasa przypadków
O klasach przypadków (case class
) więcej napisałam tutaj: Fajne rzeczy w Scali: klasy przypadków. Klasy przypadków to specjalne klasy, których instancje można porównywać przez wartość i dopasowywać do wzorców w ramach instrukcji match
.
Cecha
Cechy (trait
) są podobne do klas i umożliwiają wielokrotne dziedziczenie (które ostatecznie i tak jest linearyzowane przez kompilator, ale nie o tym teraz). Różne byty (klasy, obiekty, cechy) w Scali mogą rozszerzać jedną tylko klasę, ale za to wiele cech.
Przy dziedziczeniu z kilku cech
trzeba użyć słowa kluczowego with:
1 |
class K extends A with B with C |
Jeśli wśród “rodziców” znajduje się jakaś klasa, musi ona zostać wymieniona pierwsza, zaraz po słowie extends
.
Nie można tworzyć instancji cech.
Cechy można dodawać do klas na etapie ich definicji, ale także do instancji na etapie ich tworzenia. Cechę można dorzucić do właściwie każdej klasy – chyba że ograniczymy listę dozwolonych typów przy użyciu słowa kluczowego self
(co ma sens np. jeśli kod którejś z metod odwołuje się do pola istniejącego tylko w danej hierarchii klas).
Obiekt
Obiekt (object
) w Scali to klasa, która może miec maksymalnie jedną instancję – a więc, innymi słowy, singleton. Instancja ta zostanie utworzona w momencie pierwszego dostępu do niej przez JVM. Obiekty umożliwiają tworzenie odpowiedników metod i pól statycznych (globalnych), tj. atrybutów niepowiązanych z konkretną instancją klasy.
Obiekt może dziedziczyć z jakiejś klasy albo cechy.
Często stosowanym wzorcem w Scali są obiekty towarzyszące. Obiekt towarzyszący ma taką samą nazwę jak klasa, jest definiowany w tym samym pliku i ma (z wzajemnością) dostęp do jej prywatnych pól i metod. Obiekty towarzyszące mogą pełnić funkcję fabryki instancji danej klasy.
Kolejne zastosowanie obiektów to aplikacje w linii poleceń. Wewnątrz obiektu można zdefiniować metodę main
, która zostanie uruchomiona po wywołaniu kodu z linii poleceń.
1 2 3 4 5 |
object Hello { def main(args: Array[String]) { println("Hello, World!") } } |
Instancja
Instancja to instancja 🙂 czyli konkretny jeden byt stworzony w oparciu o wzór opisany w ramach klasy.
Przyznam, że w mojej własnej głowie nietypowe użycie słowa object
narobiło sporo zamieszania. Podejrzewam, że w miarę poznawania języka zrozumiem, dlaczego tak się stało i przestanie mnie to zaskakiwać.
Gdzie znaleźć więcej szczegółów?
Oto kilka źródeł dogłębniej tłumaczących omawiane to różnice: