Scala İle Design Pattern Denemeleri 2

October 24, 2016

Scala gibi fonksiyonel bir dil ile kod yazmanın avantajlarından bir tanesi de OOP patternları fonksyionel versiyonları ile değiştirmeye itecek bir beyin jimnastiğini tetikliyor olması. Bir önceki yazımda tam fonksiyonel olmasada Observer patternini Scala’da kodlamıştım.

Şimdi ise Wrapper/Decorator patternini fonksiyonel bir şekilde kodlamaya çalışacağım.

Decorator Pattern

Bir nesneye dinamik ya da statik yollarla istediğimiz davranışı, özelliği vermemize yarayan bir design patternidir.

Örneğin bir email nesnemiz var ve gönderdiğimiz her emailin sonuna şirket imzası koymak istiyoruz, eğer email şirket dışı alıcıya gidiyorsa. Evet sana göz kırptım beyaz yakalı, 10000 karakterli türkçe ingilizce disclaimer bulunan emaillerin sahibi  :)

Oop ile kodlanması sanırım kabaca böyle olur. Gördüğünüz üzere Email interfaceinden türetilmiş bir concrete bir Email sınıfımız ve yine aynı interfaceden türetilmiş Decorator nesnemiz bulunmakta. Bu decorator nesnesini kullanarak ilgili özelliği Email nesnesine sağlamış oluyoruz.

trait Email {

  def body: String

}

case class EmailImpl(body: String) extends Email


abstract class EmailDecorator extends Email {

  protected val email: Email
}

case class ExternalEmailDecorator(protected override val email: Email) extends EmailDecorator {

  override def body: String = email.body + disclaimer

  private val disclaimer: String =
    """
      |************************************************************************
      |The information contained in this message or any of its attachments may be confidential and is intended for the exclusive use of the addressee(s).
      |Any disclosure, reproduction, distribution or other dissemination or use of this communication is strictly prohibited without the express permission of the sender.
      |The views expressed in this email are those of the individual and not necessarily those of BigBadAssCorp or BigBadAssCorp affiliated companies.
      |BigBadAssCorp email is for business use only.
      |This email and any response may be monitored by BigBadAssCorp to be in compliance with BigBadAssCorp's global policies and standards
    """.stripMargin

}


object EmailSender {

  def send(to: String, email: Email) = {

    if(!to.endsWith("@bigbadass.com")) {

      val decorator = ExternalEmailDecorator(email)
      send(to, decorator.body)
    }
  }

  def send(to: String, body: String): Unit = {
    //Send to email client
    println(s"$to -> $body")
  }
}

Fonksiyonel yaklaşım ise her zamanki gibi çok daha az satır kod ile ifade edilebiliyor. En önemli nokta burda emailMaker fonksiyonu. Bu fonksiyon parametresiz String dönen bir fonksiyonu parametre olarak alıyor ve kendisi parametre olarak Email alan ve tekrar Email dönen bir fonksiyon geri dönüyor. Bu işlemi yaparken de kendisine parametre olarak gelen fonksiyonu kullanarak ilgili Email nesnesine ilgili özelliği eklemiş oluyor.


...

def disclaimer(str: String): String = str +
    """
      |************************************************************************
      |The information contained in this message or any of its attachments may be confidential and is intended for the exclusive use of the addressee(s).
      |Any disclosure, reproduction, distribution or other dissemination or use of this communication is strictly prohibited without the express permission of the sender.
      |The views expressed in this email are those of the individual and not necessarily those of BigBadAssCorp or BigBadAssCorp affiliated companies.
      |BigBadAssCorp email is for business use only.
      |This email and any response may be monitored by BigBadAssCorp to be in compliance with BigBadAssCorp's global policies and standards
    """.stripMargin


  def emailMaker(func:String => String) = {
    (email: Email) => {
      new Email {
        override def body: String = func(email.body)
      }
    }
  }

  val disclaimerDecorator = emailMaker(disclaimer)

  def sendFunctional(to: String, email: Email) = {

    if(!to.endsWith("@bigbadass.com")) {

      val newEmail = disclaimerDecorator(email)
      send(to, newEmail.body)
    } else {
      send(to, email.body)
    }

  }

 ...

Postta paylaştığım kodların tamamına buradan ulaşabilirsiniz.

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.