Scala İle Design Pattern Denemeleri 1

September 27, 2016

Bir süredir Scala ile alakalı blog yazma isteğim vardı. Nasıl giriş yapacağıma bir türlü karar verememiştim. Fakat bugün gördüğüm şu posttan sonra gerekli motivasyona sahibim artık :)

"Java enterprise implementation of observer pattern"

“Java enterprise implementation of observer pattern”

Bu post tabi Classic Programming Paintings tumblr hesabından geliyor, çok güzel paylaşımlar var şiddetle takip etmenizi öneriyorum ayrıca.

Çalıştığım projede bir kaç gün önce birebir aynı olmasa da observer patternina yakın bir çözüm üretmem gerekmişti.
Observer patterni isminden de anlaşılacağı gibi aslında belli sayıda gözlemcinin bir nesne üzerindeki değişikliklerden haberdar olmasını sağlayan bir oop patterni.

Problem

Belli başlı kaynak tutan classların/singleton objelerin düzgün bir şekilde kapatılması. Bu önemli bir konu çünkü bir çok noktada ilgili kaynakların leak olmasına sebep olup; uygulamaya beklenmedik hatalar verdirebilir.

Çözüm

Probleme brute force yaklaşıp ilgili yerde obj.close() şeklinde tabi ki çözebiliriz. Bu yaklaşımın en büyük sorunu kapatacağımız nesneleri önden bilmiyor oluşumuz. Yani kapatmak istediğimiz object singleton bir Object X olabileceği gibi ilgili katmanda var olmayan yani encapsulate edilmiş başka bir instance da olabilir. Ayrıca şu satırların gereksizlğini ve çirkinliği sizlere bırakıyorum :)

Object1.close
Object2.close
intance.close
socketWrapper.close
..

Observer Pattern

Observer patterni Subject vs Observer olmak üzere iki ayrı yapıdan meydana gelmektedir. Subject kendisi üzerinde olan herhangi bir durum değişikliğini yine kendisine üye olan observerlara; bu gözlemcilerin bir metodunu çağırarak bildirir. Gördüğünüz gibi oldukça basit generic bir yaklaşım.

Bizim proje için oluşturduğumuz örnek Subject ve Observer yapıları şu şekilde gözükmekte;

trait Observer {

  def observe
}

trait Subject[T <: Observer] {

  protected val observers: mutable.ListBuffer[T] = new mutable.ListBuffer[T]

  def addObserver(o: T): Unit = {
    observers += o
    return
  }

  def removeObserver(o: T): Unit = {
    observers -= o
    return
  }

  def notifyObservers = observers.foreach(_.observe)
} 

Bu traitleri extend ederek istediğiniz her tip eventi tetikleyip observerları haberdar edebilirsiniz.
Bizim probleme tekrar dönersek, closable observerları close eventi için haberdar etmek istiyorum. Bunu gerçekleştirmek için yapmamız gereken tek şey bu iki traiti extend etmek;

trait CloseableObserver extends Observer with Closeable {

  override def observe: Unit = close()

}

object CloseableSubject extends Subject[CloseableObserver]

Gördüğünüz gibi artık CloseableSubject aracılığı ile yeni closeable observerlar eklemek oldukça basit. Ayrıca CloseableObserver java.io.Closeable‘i extend ettiği compile time da ilgili clientları close metodunu implement etmeye zorluyoruz. Bu şekilde CloseableSubject notifyAll yaptığında tüm observerların close methodu çağrılmış olacak.

Evet tüm parçalar artık hazır olduğuna göre nasıl kullanacağımızı görebiliriz;

object KafkaAction
  extends ActionRunner
    with ActionRegister
    with CloseableObserver
    with LazyLogging {
    
    ...
    ...
    
   override def close: Unit = {
      logger.info("Object is closing resources")
      resource.close
      resource2.close
  }
}


//CloseableObserver'i extend etmiş herhangi bir class'in instance'i kendisini gözlemci olarak kaydedebilir
//Diğer nesneler için ise derleyici type hatası verecektir  
CloseableSubject.addObserver(actionRunner.asInstanceOf[CloseableObserver])

Evet artık observerlar kendilerini register ettiler dolayısı ile istediğimiz anda tüm gözlemcileri close eventi ile alakalı haberdar edebiliriz.

sys addShutdownHook {
  logger.info("Shutdown request initiated")

   CloseableSubject.notifyObservers     
}

Evet observer patterni basit hali ile bu şekilde. Siz kendi probleminize göre daha farklı subject yapıları oluşturabilirsiniz. Bu şekilde sadece eventi değil, değişen state’i de bildirebilirsiniz gözlemcilere.
Observer patterni ile alakalı daha detaylı bilgi için wiki sayfasına bakabilirsiniz ayrıca.

Bu noktaya kadar sıkılmadan okuduğunuz için teşekkür ediyorum, sorularınız olursa alttaki disqus kutucuğundan gönderin lütfen.