Dlaczego Scala jest dobrym pomysłem przy Vaadin?
Vaadin jest frameworkiem dobrym. Ma jasno określone cele, wymagania oraz zapotrzebowanie na zasoby. API jest niczego sobie, a jak nam mało to zawsze możemy do pracy zaprząc GWT i frameworki JavaScriptowe. Ma jednak to API jedną straszną wadę…
// DOWCIP
W C metody nie mają nazw opisowych.
W php nazwy czasami są opisowe, czasami nie, a do tego nie trzymają się konwencji w nazewniczej.
W Javie metody mają nazwy opisowe, tzn. po sygnaturze wiesz mniej więcej co metoda robi.
W Ruby metody mają nazwy opisowe, które mieszczą się w jednej standardowej linii.
// HAHAHA
Generalnie Java jest dość rozwlekłym językiem np. implementacja anonimowego interfejsu jest upierdliwa. Podobnie nie ma możliwości zastosowania częściowej implementacji (metody niezaimplementowane rzucają UnsupportedOperationException, ale wstawia to kompilator) bez wykorzystania wzorca Adapter (patrz adaptery w Swingu). Trochę szkoda, że Lombok tego nie wspiera, ale generalnie jest do dupy.
Vaadin przeniosło jednak ten specyficzny aspekt języka na nowy poziom. Generalnie jednym z moich ulubionych rozwiązań są wewnętrzne interfejsy dla listenerów (np. Button.ClickListener). Pozwala to na wyklarowanie naszych klas i jasno rozdziela kod listenerów dla konkretnych elementów UI. Nie ma też już uniwersalnych listenerów opartych na drabince ifów sprawdzającej źródło zdarzenia. Jednocześnie jednak nazwy zaczynają być bardzo długie, a przy implementacjach anonimowych naprawdę przestaja się mieścić w standardowych 80 znakach na linię…
Tu na ratunek przychodzi Scala i jej mechanizm funkcji. W uproszczeniu jako parametr metody/konstruktora możemy przekazać funkcję, która zostanie wywołana wewnątrz tejże metody. Przypomina to trochę mechanikę wskaźników na funkcje znanych z C, gdzie można było np. ustawić jako jeden z elementów struktury wskaźnik na funkcję i już mieliśmy taką okrojoną klasę.
Poniżej przykład implementacji Button.ClickListener, która jest „w miarę krótka”.
Listing 1. Klasa UBCL.scala
class UBCL(m: =>Unit) extends Button.ClickListener{
def buttonClick(p1: ClickEvent) {
m
}
}
Oraz jej zastosowanie w przykładzie z poprzedniego wpisu:
Listing 2. Klasa MyVaadinUI.scala
class MyVaadinUI extends UI {
var liczby: List[Int] = List(0)
override def init(request: VaadinRequest) {
val layout = new VerticalLayout()
layout.setMargin(true)
setContent(layout)
val liczbyLabel = new Label("0")
val input: TextField = new TextField("Podaj liczbę")
input.setValue("0")
val kolejnaBtn: Button = new Button("Kolejna")
kolejnaBtn.addClickListener(new UBCL({
liczby ::= input.getValue.toInt
liczbyLabel setValue liczbyLabel.getValue + "+" + input.getValue
input.setValue("")
input.focus()
}))
val sumaBtn = new Button("Suma")
sumaBtn.addClickListener(new UBCL({
// sumowanie liczb
val wynik: Label = new Label(liczby.foldLeft(0) {
(a, b) => a + b
}.toString)
layout.addComponent(wynik)
liczbyLabel.setValue("0")
liczby = List(0)
}))
layout.addComponent(input)
layout.addComponent(kolejnaBtn)
layout.addComponent(liczbyLabel)
layout.addComponent(sumaBtn)
}
}
jak widać udało się „obciąć” definiowanie metody buttonClick na rzecz użycia funkcji.