niedziela, 24 listopada 2013

Wzorzec Command w inny sposób

Ponieważ nie umiem wymyślić ciekawego wstępu do artykułu o wzorcu projektowym dlatego nie tak od razu przejdę do rzeczy. Doszło do mnie kilka opinii (zwłaszcza wczoraj przy wódzie - ja tam dużo nie piję bo to nie jest zdrowe ale inni tak), że poprzedni wpis był za długi i było w nim za mało cycków. Po pierwsze to ludzie wstydźcie się bo takie uwagi są w ogóle bardzo bardzo niedobre, bardzo bardzo złe. Po drugie chociaż bardzo bym chciał to jednak wydaje mi się, że nie mogę sobie wklejać losowych cycków (nawet tych sztucznych) z internetu bo to łamie jakieś tam prawa autorskie. Pozostaje mi tylko nauczyć się rysować cycki w paincie co może nie być złym pomysłem zważywszy na to, że zawsze kiedy koloruję ramki tabelek w css odczuwam niesamowity relaks i spadek ciśnienia krwi.

Wzorzec command bardziej funkcyjnie

Na Wikipedii wzorzec jest opisany i jest nawet przykład w scali - ale ów przykład wydaje mi się trochę lewy :http://en.wikipedia.org/wiki/Command_pattern

Jakby to można było napisać inaczej ?

 type Command = () => Unit
 type KanalInformacji= String=>Unit
Na początku dla porządku zadeklarujmy dwa typy. Ponieważ komenda standardowo ma metodę execute, która nic nie zwraca, więc i tutaj mamy "funkcję" bezzwrotną i bezparametrową. A KanalInformacji to taki typ dla bajeru, że niby wysyłamy coś kanałem informacji. Dodatkowo ostatnio przeczytałem, że posługując się innymi językami ludzie używają trochę innych rejonów w mózgu, więc taki ponglish może być ciekawym sposobem aby zyskać nową perspektywę

 class Egzekutor {
    var historia: Vector[Command] = Vector()
  
  def execute(command:Command)={
   historia=historia :+ command
   command()
  }
  
  def replay()={
   historia.foreach(_.apply)
  }
  }
W odróżnieniu od filmu z Arnoldem powyższy egzekutor po prostu wykonuje komendy i zapisuje je w historii coby replaya strzelić jak trza.

def commandFunction(kanalInformacji:KanalInformacji)(wiadomosc:String)()={
  kanalInformacji(wiadomosc)
}     
def wyslijNaEkran(wiadomosc:String)=println(wiadomosc)
val ekranCommand=commandFunction(wyslijNaEkran)_
val ekranONCommand=ekranCommand("ON")
val ekranOFFCommand=ekranCommand("OFF")
To jest bardzo ale to bardzo ciekawy fragment. PNie wiem jak w tej kolorowance kodu pogrubić konkretne fragmenty także powiem na co trzeba zwrócić uwagę
  1. Trzecia para nawiasów w pierwszej linii. To jest potrzebne aby po wywołaniach w liniach 6 i 7 nie otrzymać wartości a funkcję bezparametrową : ekranONCommand : () => Unit = <function0>. Jeśli można inaczej to ja nie znam.
  2. W linii piątej jest na końcu taki podkreślnik, który oznacza, że aplikujemy tylko pierwszy argument do funkcji i w wyniku mamy : ekranCommand : String => (() => Unit) = <function1>
  3. I generalnie jest zajebista kompozycja. Można sobie tworzyć wiele kanałów komunikacji i wysyłać wiadomości

    egzekutor.execute(ekranONCommand)         //> ON
 egzekutor.execute(ekranONCommand)         //> ON
 egzekutor.execute(ekranOFFCommand)        //> OFF
 egzekutor.execute(ekranOFFCommand)        //> OFF
 egzekutor.execute(ekranONCommand)         //> ON
 egzekutor.replay                          //> ON
                                                  //| ON
                                                  //| OFF
                                                  //| OFF
                                                  //| ON
I elegancko:

Posłowie (W sensie literackim a nie ci złodzieje!)

No i widzimy, że można sobie ładnie zaimplementować wzorzec Command przy pomocy funkcji. Nie wiem czy to tutaj przedstawiłem w 100% pokrywa się z klasycznym wzorcem ale tak w głębi serca mnie to jebie. Pozostaje jeszcze jedna kwestia - co jeśli nie znasz scali i nie możesz rozszyfrować co w tym kodzie jest popisane? Nie przejmuje się - kim jesteś? JESTEŚ ZWYCIĘZCĄ!!!!

*      *      *

Brak komentarzy:

Prześlij komentarz