Groovy in action, czyli to co tygrysy lubią najbardziej

Zdałem sobie sprawę, iż powoli w swoich postach wychodzę poza klasy dziedzinowe/domenowe i z pola związanego z GORM wypada przejść do bardziej ‘programistycznych’ rzeczy, czyli do kontrolerów i widoków. I co z tego?

Ano to z tego, iż w tych elementach MVC przyda się kilka słów wyjaśnienia dotyczących języka Groovy. Prostota Grailsów umożliwia rozpoczęcie z nimi pracy bez lepszej znajomości języka Groovy. Jednakże jest to taka sama sytuacja jak w przypadku RoRa – pewnym momencie nieznajomość języka bazowego doprowadza do zatrzymania w rozwoju, ba, wręcz konieczności cofnięcia się w nauce. Dlatego też uprzedzając ten stan rzeczy dziś artykuł dotyczący kilku charakterystycznych dla Groovy’ego konstrukcji i rozwiązań.

Na pierwszy ogień idąc domknięcia (ang. closures). Jak piszą w mądrych książkach – “Domknięcia nie są trudne, są inne.” Myślę, że jest to najlepszy możliwy ich opis. Mówiąc zaś w skrócie – domknięcia są to obiekty, które zachowują się jak metody. Mogą przyjmować parametry, mogą zwracać wartość. Takie pomieszanie z poplątaniem, ale dzięki temu jest to konstrukcja kosmicznie wręcz skalowalna i efektowna (o efektywności pewnie kiedyś napiszę). Drugą definicją może być proste stwierdzenie, iż domknięcie to zwykły obiekt, który jest związany z pewnym fragmentem kodu. Jest to może mniej inticyjne, ale mam nadzieję, że przykłady pokażą o co chodzi.

Domknięcia można tworzyć tak:
– “w przelocie”
suma = 0
(1..10).each{ cyferka -> suma += cyferka }

– “z przypisaniem do zmiennej” (do tej pory używane przeze mnie w przykładach)
suma = 0
def domkniecie = { cyferka -> suma += cyferka }

Rozebrać należy ten temat na czyniki pierwsze. Otóż naturalnym odruchem dla programisty Groovy’ego powinno być myślenie – “nawiasy klamrowe, o, domknięcie”!!! Niezależnie od użytej formy ich tworzenia, zawsze jest to domknięcie. Konstrukcja ze strzałką przypomina PHP, ale jej znaczenie i istota jest daleka od odwoływania się do obiektu w PHP. Pewnie zresztą już jest jasne o co chodzi – wszystko, co jest po lewej stronie strzałki to parametry, które są przekazywane do domknięcia (jako parametry metody). To zaś, co znajduje się po prawej stronie strzałki to najzwyklejsze ciało metody. W przypadku domknięć do których przekazujemy tylko jeden parametr, nie wymaga on deklaracji, zaś w kodzie można odwoływać się do niego za pomocą domyślnej zmiennej it, np:

def domkniecie = { println it }
domkniecie("Tutaj chlebik");

Istnieje też trzecia możliwość stworzenia domknięcia. Wystarczy, że dysponujemy metodą w klasie, np:

class Rysowanko {

public void narysujCos( String tekst ) {
System.out.println( tekst );

}
}

To by potraktować tę metodę jako domknięcie wystarczy taka konstrukcja:

Rysowanko egzemplarzDoRysowania = new Rysowanko();
def rysujaceDomkniecie = egzemplarzDoRysowania.&narysujCos;
rysujaceDomkniecie( "Tutaj chlebik po raz drugi!" );

Czyli tworzymy domknięcie w formie pewnego typu wskaźnika do metody. Do czego to się może przydać? Ano na przykład mamy klasę taką jak powyższa, w której znajduje się kilka przeciążonych metod ( parametry to string, jakieś numerki, może jeszcze inne obiekty z własnymi metodami toString). Deklarujemy domknięcie dla tej przeciążonej metody i… i w zależności od przekazanych do domknięcia parametrów wywołuje ono konkretną metodę. Miłe, fajne i przyjemne. Zainteresowanych tematem odsyłam do dokumentacji Groovy, gdzie można sobie na ten temat poczytać więcej.

Innym dość ciekawym elementem języka są operatory specjalne. Znacząco potrafią ułatwić życie programiście, zwłaszcza w kontekście kontrolerów i widoków. Oto one:

  • spread operator ( *. ) – oznacza w skróconym zapisie, iż należy daną metodę/domknięcie wykonać na wszystkich elementach zbioru na rzecz którego została ona wywołana. Ufff, zamotałem. Oto kod:
    def lista = ["Chlebik ", "to ", "kiepski ", "programista."]
    print( lista*.toString() )

    Wyświetli on zgodnie z oczekiwaniami wszystkie elementy listy w formie ciągu wyrazów oddzielonych spacjami
  • Elvis operator ( ?: ) – bardzo przyjemna rzecz, która pozwala nadać zmiennej domyślną wartość na wypadek, gdyby przez przypadek z przypisania wyszły nici (zwrócona wartość to null lub jest po prostu pusta). Kod:
    tekst = jestemObiektem.wyciagnijMojaNazwe()?:"nie wiadomo"
  • Null-safe deference ( ?. ) – pamiętacie te wszytkie konstrukcje IF NOT NULL (lub coś w tym guście)? W Groovy istnieje operator, który wyręcza nas w tej brzydkiej czynności. Oto kod:
    println( zmiennaMogacaBycNullem?.jakiesJejPoleLubMetoda )"
    Jeżeli potencjalny obiekt, którego metodę chcielibyśmy wywołać okaże się być NULL to po prostu nic nie nastąpi. Tyle.

Na sam koniec zostawiłem tzw. Expando. Kolejna rzecz z ‘dynamicznej’ części Groovy, która jednakże może budzić pewne obawy. Zwrócił na to uwagę Jacek Laskowski w swojej prezentacji na WJUGu. Ale do rzeczy. Expando to po prostu obiekt, który zachowuje się w sposób, który określamy ‘na bieżąco’, bez konieczności tworzenia oddzielnej klasy lub pliku. Wkleję może przykład z książki:

def user = new Expando()

user.firstName = 'Christopher'
user.lastName = 'Judd'

user.greeting = { greeting ->
"${greeting} ${firstName} ${lastName}"
}

assert user.greeting("Hello") == 'Hello Christopher Judd'

Jak widać do takiego Expando możemy przypisać pewne wartości, zaś zachowanie (metody) deklarujemy poprzez domknięcia. Świetna sprawa, zwłaszcza by nie zaśmiecać kodu klasami wewnętrznymi.

To tyle jeśli chodzi o ten ciekawy język. Oczywiście rzecz jasna poruszyłem raptem trzy zagadnienia, jednakże uczyniłem tak tylko z powodu wyjaśnienia kilku rzeczy, które na 100% pojawią się w kolejnych wpisach, a wiedza o nich jest konieczna. Zainteresowanych poznaniem Groovy od podszewki zapraszam na oficjalne strony projektu. Można też zaopatrzyć się w literaturę poświęconą zagadnieniu, albo też skorzystać z masy linków, które prowadzą do miejsc związanych z Groovy.

Advertisements

One thought on “Groovy in action, czyli to co tygrysy lubią najbardziej

  1. Krzysiek

    Fajny post, muszę popracować nad zrozumiałymi postami u siebie 😉
    Dodałbym może, że tak naprawdę doklejać zachowanie możemy na różne sposoby, a Expando to po prostu ułatwia. Zwykła mapa wygląda podobnie i możemy ją nawet rzutować na typ 🙂

    interface Kaczka{
    void kwa()
    void lataj()
    }

    def mapa = [ kwa:{println ‘kwa’}, lataj: {println ‘ja latam!’} ]
    def kaczka = mapa as Kaczka

    Świetna sprawa, zwłaszcza przy pisaniu testów. To co robi Expando, to pozwala definiować domknięcia tak jakbyśmy pisali funkcje w normalnej klasie (domknięcia widzą jej zawartość) i np. nie trzeba pisać user.greeting = { greeting -> “${user.firstName}” } tylko samo “${firstName}” co jest zdecydowanie lepsze 🙂

    Pozdrawiam,
    Krzysiek

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s