niedziela, 29 marca 2015

Traity ortogonalnie i nieortogonalnie

"Wiem, że nie wiem" to tzw. poziom świadomej niekompetencji kiedy miejsce ignorancji zastępują pytania bez odpowiedzi.

I takie właśnie pytanie pojawiło się na ostatnim warsztacie - jak dobrze zmodyfikować zachowanie klasy przy pomocy Traita tak by ona nic o tym nie wiedziała. Na miejscu niestety nie udało mi się odpowiedzieć ale teraz mamy drugą szansę.

Ortogonalne

Ortogonalne to to samo co prostopadłe ale brzmi mądrzej. W tym przypadku nie ma modyfikacji zachowania klasy jako takiej ale Trait dodaje zupełnie nową funkcjonalność - tutaj logowanie.

abstract class Actor {
    def receive(s:String):Unit
}

//wersja oryginalna
class EchoActor extends Actor {
    override def receive(s:String)=println(s"echo $s")
}

//wersja z mixinem
class EchoActor extends Actor with Logging{
    override def receive(s:String)={
        logger.log(s)
        println(s"echo $s")
    }
}


trait Logging{
    class Logger{
        def log(s:String)=println(s"LOGGING : $s")
    }
    val logger=new Logger
}

 new EchoActor().receive("message")

I teraz pytanie jak to zrobić by dodać to logowanie ale bez modyfikacji EchoActor?

Podejście pierwsze - self type

Trzeba trochę eksperymentować w życiu i nie zrażać się tym, że czasem nie wychodzi. Bo teraz to co napiszę nie zadziała.

//ten kawalek/mechanizm "self:Actor=> " nazywa się "self-type" i daje traitowi
//wiedzę, z jaką klasą będzie zmiksowany
trait NonOrthogonalLogging1{self:Actor=>
    
    def cosTam(){
      self.receive("aaa")
    }
//chociaz nie dziedziczymy po aktorze to trzeba dać override bo inaczej będzie się walić przy miksowaniu    
    override def receive(m:String):Unit={
      println(s"INFO : ${m}")
//nie można tutaj użyć super bo teoretycznie dziedziczymy z AnyRef
      self.receive(m)
    }
  }

//no i koniec końców nic niespodziewanego się nie dzieje, "self.receive" wywołuje metodę z traita a nie z klasy i cały program się zapętla.
val echo=new EchoActor() with NonOrthogonalLogging1
echo.receive("test")

Podejście drugie - dziedziczenie klasy abstrakcyjnej

trait NonOrthogonalLogging2 extends Actor{self:Actor=>
    
//to jest dziwne, trzeba dać abstract bo inaczje kompilator sie pluje, ze receive z nadklasy jest abstract.
    abstract override def receive(m:String):Unit={
      println(s"INFO : ${m}")
      super.receive(m)
    }
  }
  
  class EchoActor extends Actor{
    def receive(m:String)=println(s"ECHO ${m}")
  }

   //no i to już działa
   val echo=new EchoActor() with NonOrthogonalLogging2
   echo.receive("test")

//INFO : test
//ECHO test

Oczywiście, jeśli ktoś wie jak to zrobić lepiej niech śmiało da znać.

Warsztat

Na warsztat http://www.meetup.com/Java-User-Group-Lodz/events/221347512/ zapisało się 25 osób +15 jest na liście oczekujących co daje 40 osób zainteresowanych nauką Scali. Fajnie, że ludzie są zmotywowani do nauki Scali i to także motywuje mnie, żeby robić te warsztaty.

Niedawno na EDX był kurs szczęścia- dosłownie kurs szczęścia EDX : Science of hapiness. - bazujący na ciekawym dziale psychologii czyli Psychologii pozytywnej. Motyw działalności w lokalnych społecznościach pojawiał się tam dosyć często.

Więcej można o tym poczytać sobie też tutaj : http://www.actionforhappiness.org/10-keys-to-happier-living/local-community/details. Interakcje społeczne zwiększają nasilenie wytwarzania oksytocyny, która jest hormonem antagonistycznym do kortyzolu co generalnie poprawia nastrój i tak dalej.

1 komentarz: