niedziela, 1 grudnia 2013

Wzorzec Stan w inny sposób

Był swego czasu taki kabareciarz, zwący się Stan Tutaj ale to nie ma żadnego związku z tym artykułem gdyż ja chcę opisać wzorzec Stan tutaj.

Stan

Na necie ilustrację dla tego wzorcu stanowi przykład z włącznikiem światła, który jest totalnie nieludzki tak jak dzisiejsze czasy. Lepszym pomysłem jest wykorzystanie stanu pięknego związku uczuciowego łączącego dwie istoty ludzkie (zazwyczaj o odmiennej płci ale nie wnikam). Dla uproszczenia ograniczymy się do tych dwóch :
  • Kocha
  • Nie Kocha
A zapomnimy o tych stanach :
  • To skomplikowane
  • Graliśmy w słoneczku ale jeszcze ze sobą nie chodzimy

Kod

W obiektówce tworzyło się obiekt, który opakowywał dostęp do stanu i takie tam. Czyli tutaj mielibyśmy coś co symbolizuje związek (miłosny nie Radziecki) i zmiany jego stanu. Ale można też inaczej - zaimplementujmy zmianę stanu... bez zmiany stanu.
def kocha(licznikLudowy:Int):String= if(licznikLudowy==0) "Kocha" else nieKocha(licznikLudowy-1)
def nieKocha(licznikLudowy:Int):String=if(licznikLudowy==0) "Nie Kocha" else kocha(licznikLudowy-1)

kocha(10)                                       //> res0: String = Kocha
kocha(11)                                       //> res1: String = Nie Kocha
Niby fajnie ale teraz się wywali :
 kocha(100000)                                   //> java.lang.StackOverflowErrorSexuNieBedzie

Niestety nie starczyło miejsca na stosie na tyle wywołań tychże dwóch funkcji (stos w informatyce to miejsce gdzie pali się czarownice).

Trampolina

Internet zna rozwiązania tego problemu z zastosowaniem techniki zwanej trampoliną (albo czymś co się wymawia podobnie ale znaczy coś zupełnie innego). Idea jest taka aby ograniczyć skoki do kilku komórek na stosie - czyli takie "Tail recursion" dla kilku funkcji na raz.
def kocha(licznikLudowy:Int):TailRec[String]= if(licznikLudowy==0) done("Kocha") else tailcall(nieKocha(licznikLudowy-1))
def nieKocha(licznikLudowy:Int):TailRec[String]=if(licznikLudowy==0) done("Nie Kocha") else tailcall(kocha(licznikLudowy-1))

kocha(100000).result                            //> res0: String = Kocha

Typ zwracany to już nie jest zwykły string ale String opakowany w TailRec. No i metody wywołujemy poprzez done i tailcall. Będę musiał kiedyś doczytać jak pogrubia się tekst w tej kolrowaczce do kodu.
*      *      *

3 komentarze:

  1. kurcze po twoim wyjaśnieniu nadal nie wiem co robi wzorzec stanu.
    tzn głupi jestem ?

    OdpowiedzUsuń
  2. Artykuł ewidentnie pisany na kwasie;)
    Ale w pozytywnym sensie, uśmiałem się. Dzięki!

    OdpowiedzUsuń