Design Patterns — Behavioral

Mert Kimyonşen
8 min readOct 11, 2020

Bir önceki yazı için Design Patterns — Structural

Tasarım kalıplarını tanıma ve öğrenme sürecinin son basamağı ve aynı zamanda serinin sonu niteliğinde olan Behavioral Design Patterns (Davranışsal Tasarım Kalıpları) sıra geldi. Bu süreçte tasarım kalıpları için kendi adıma güzel bir türkçe kaynak oluşturduğumu düşünüyorum.

Yine bu yazı ile birlikte her bir tasarım kalıbını tecrübe ettiğim kod örneklerini de github’a yükledim.

Behavioral Design Patterns nesnelerin çalışma zamanında sergiledikleri davranışları değiştirmek için kullanılan tasarım kalıplarından oluşur.

Gof kitabına göre Behavioral Design Patterns 11 adet tasarım kalıplarından oluşur;

  • Observer Pattern
  • Chain of Responsibility Pattern
  • State Pattern
  • Mediator Pattern
  • Command Pattern
  • Iterator Pattern
  • Interpreter Pattern
  • Strategy Pattern
  • Template Method Pattern
  • Visitor Pattern
  • Memento Pattern

Observer Pattern

Birbirine one-to-many olarak bağlı olan nesnelerin birinde (one) gerçekleşen değişiklikleri ona bağlı olan diğer nesnelere (many) durumunu haberdar etmek için kullanılır. Yani bir nesneye abone olunuyor (subscribe) ve bu nesne üzerinde gerçekleşen değişimler abone olan diğer nesnelere; hey benim durumum değişti bi bak istersen! diye haberdar ediyor 😊

Ne Zaman Kullanmalıyız

  • Bir nesnede meydana gelen değişimler ve ona bağlı olan diğer nesneleri etkilemesini istiyorsak
  • Değişimini izlemek istediğimiz nesnelerle çalışmak istiyorsak

Observer Pattern aynı zamanda loosely-coupled ilişkisi vardır. Yani iki obje birbirleri ile ilişkilidir ama birbirleri hakkında çok az şey bilirler

Kullanım Sıklığı

  • Yüksek -> %100

UML Diagram

  • Subject: Takip edilecek olan nesne. Durumu değiştiğinde gözlemcilere haber verir.
  • Observer: Abstract gözlemci sınıfımız. Birden fala gözlemci tek bir çatıda toplanmasını ve takip edilmesini sağlar
  • ConcreteObserver: Observer’ı uygulayan gerçek nesnemiz.

Observer Pattern Kod Örneği

Chain of Responsibility Pattern

Sisteme gönderilen bir komutun (command) birbirleri ile loosley-coupled şekilde bağlı olan nesneler arasında gezdirilmesi ve asıl sorumlu tarafından ele alınması (handle) ancak ele almadığı durumlarda komutu zincirdeki bir sonraki nesneye iletmesi için kullanılan tasarım kalıbıdır. Kısacası; bir işlemi yapabilecek birden fazla sınıftan hangisinin yapabileceğine karar veren bir tasarım kalıbıdır.

Ne Zaman Kullanmalıyız

  • If-else, switch yapılarının çok fazla olduğu kod karmaşasını engellemek istiyorsak
  • Bir işlemi sırasıyla ele almak istiyorsak
  • İsteği oluşturan (request) ve bu isteği ele alan (handle) arasında loosely-coupled bir ilişki kurmak istiyorsak

Kullanım Sıklığı

  • Orta düşük -> %40

UML Diagram

  • Diktat çeken Handler ile ConcreteHandler arasında Aggregate söz konusu. Bunun olması çok doğal çünkü zincirdeki bir sonraki elemana bu referans ile aktarım yapılacak.
  • Handler: Çatı sınıfımız. Abstract ya da interface olabilir. Kendisinden türeyen sınıflar için arayüz niteliğindedir.
  • ConcreteHandler: Sorumlu olduğu işi ele alan gerçek nesnemiz. Gerekirse işi zincirin bir sonraki halkasındaki nesneye aktarır.
  • Client: talebi gönderen

Chain of Responsibility Pattern Kod Örneği

Mediator Pattern

Nesnelerin yönetimini ve aralarındaki iletişimi merkezi bir yerden sağlanması ve yönetmesi için kullanılan tasarım kalıbıdır. Nesneler arasında loosley-coupled bir şekilde ilişki sağlar ve bir sınıfı yönetici sınıf olarak diğer sınıfların koordineli çalışması için sorumlu tutar.

Ne Zaman Kullanmalıyız

  • Sınıflar arasındaki bağımlığı azaltmak ve aralarındaki iletişimi kolaylaştırmak istiyorsak
  • Anlaşılması zor ve yönetilmesi karmaşık olan nesnelerle çalışıyorsak

Kullanım Sıklığı

  • Orta yüksek -> %40

UML Diagram

  • Yukarıda görüldüğü gibi Colleague’den Mediator’a doğru, Concorete Mediator’dan ConcreteColleague sınıflarına doğru tek yönlü (Asscoation) ilişki vardır.
  • Mediator: Çatı sınıfımız. Abstract/Interface olabilir. Diğer sınıfları yönetecek sorumlu sınıfımız.
  • Colleague: Abstract ya da Interface olabilir. Birden fazla Colleague üretmemiz için arayüz sağlar.

Mediator Pattern Kod Örneği

Command Pattern (Komut Kalıbı)

Bir isteği bir nesne olarak kapsülleyerek (encapsulation) bir eylemi gerçekleştirmek ya da daha sonraki bir zamanda bir olayı tetiklemek için kullanılan tasarım kalıbıdır. Kısacası; yapılmak istenen işi nesneye dönüştürerek alıcı nesnesi tarafından işlemin ele alınmasını sağlar

Ne Zaman Kullanmalıyız

  • Bir isteği nesne olarak kullanmak istiyorsak
  • Nesne üzerinde bir işlemin nasıl yapılacağını bilmediğimiz ya da kullanılmak istenen nesneyi tanımadığımız durumlarda
  • İşlemi tetikleyen nesneler ile işlemi ele alan nesneleri birbirinden ayırmak istiyorsak

Kullanım Sıklığı

  • Orta yüksek -> %40

UML Diagram

  • 4 terim her zaman birbirleri ile ilişkilidir. Command, Invoker, Reveiver, Client
  • Invoker ile ICommand arasında Aggregation söz konusudur.

Aggregation sınıflar arasında parçası olma anlamı vardır. Yani bir sınıfın bir parçası olma gibi. ICommand Invoker nesnesinin bir parçasıdır ama ICommand yok olduğunda Receiver yok olma zorunluluğu yoktur aralarında zayıf bir ilişki vardır

  • ICommand: Komutların ortak türe sahip olması için tanımlanan arayüz
  • Receiver: Asıl işlemi yapacak sınıf.
  • Invoker: Komutları tetikleyecek olan sınıf. Ancak hangi komut nesnesini çağıracağını bilmez.
  • Client: Invoker sınıfını çağırır.

Command Pattern Kod Örneği

Iterator Pattern

Nesne koleksiyonlarının (list, queue, stack…) elemanlarını belirlenen bir kurala göre sırasıyla erişebilmeyi sağlayan tasarım kalıbıdır. Bu tasarım kalıbında Iterator ve Iteratable yani Enumerator ve Enumerable parçalarından oluşuyor. Iterator tekrarlayıcı, Iteratable tekrarlanan anlamına gelir. Nesne koleksiyonundaki her bir elemana for; ya da foreach; ile erişerek aslında bu patterni sık sık kullanıyoruz.

Ne Zaman Kullanmalıyız

  • Nesne koleksiyonunda yer alan elemanları sırasıyla uygulamadan soyutlamak istiyorsak
  • Koleksiyon nesnesinin belirli bir kurala göre içindeki elemanları sırasıyla erişmek istiyorsak

Kullanım Sıklığı

  • Yüksek -> %100

UML Diagram

  • Iterator: Nesne koleksiyonundaki elemanlara erişebilmek için bir arayüz sağlar.
  • Aggreagate: Tekrarlayıcı nesnelerin yaratılması için arayüz sağlar. Koleksiyon nesnemizdeki iterate edilecek elemanları temsil eder.

Iterator Pattern Kod Örneği

Interpreter Pattern

Belirli bir mantıktaki metinlerin nasıl yorumlanacağını belirleyen bir tasarım kalıbıdır. Belirli mantıktaki metin derken; cryptolanmış metin belgeleri, binary dönüştürülmüş video ya da image’ler, encode edilmiş content’ler gibi işlemler. Kural işletme motorları (Rule Engine) söz konusu olduğunda bu tasarım kalıbı kullanılır.

Ne Zaman Kullanmalıyız

  • Metin üzerinde belirli bir mantıkta yorumlama ve çevirme işlemlerini bir bütün olarak yapmak istiyorsak
  • Metindeki verilerin sayısal ve mantıksal olarak yorumlanmasını istiyorsak

Kullanım Sıklığı

  • Düşük -> %20
  • Bunun sebebi belirli bir kural gerektiren grammer yapılarında kullanıldığı için kısıtılı bir kullanımı vardır.

UML Diagram

  • Context: Yorumlanacak içerik sınıfı.
  • AbstractExpression: Abstract/Interface olabilir. Context’in yorumlanması için iş mantığını üstlenir (Business Logic)
  • TerminalExpression: Belirlenen bir mantığa göre işletilen operand barındırır.
  • NonTerminalExpression: Bazen iki Terminal’ı “or” ya da “and” operandları ile bağlayabilir. İşletme önceliği bu sınıftadır.

Interpreter Pattern Kod Örneği

State Pattern (Durum Kalıbı)

Bir nesnenin içsel durumunda (internal-state) meydana gelen değişim sonrası çalışma zamanında dinamik olarak farklı davranışları sergileyebilmesini sağlayan tasarım kalıbıdır. State Pattern aslında Workflow yapısındaki State Machine kavramının denk geliyor. Yani nesnenin durumunun değiştiğinde farklı davranışların sergilemesi, nesneye ait fonksiyonların tetiklenmesi ve bunlara bağlı olarak geçişlerin (transition) sağlanması anlamına gelir.

Ne Zaman Kullanmalıyız

  • Bir durum değiştiğinde değişen davranışları if-else, switch gibi yapılarla oluşacak kod karmaşıklığın önüne geçmesini istiyorsak
  • Bir nesnenin iç durumunda değişiklik meydana geldiğinde dinamik olarak davranış sergilemesini istiyorsak

Kullanım Sıklığı

  • Medium -> %60

UML Diagram

  • Context: internal state bilgisini tutan sınıfımız
  • Context ile State arasında bir Aggregaion söz konusu. Çünkü Context üzerinde her bir request için durum değişikliği olacak ve bunu da State referansı üzerinden yapacak
  • State: Context durumunu netleştiren ve ortak bir arayüz sağlayan sınıfımız
  • ConcreteContext: State arayüzünü uygulayan ve durumu ele alan davranışlar uygular.

State Pattern Kod Örneği

Strategy Pattern (Strateji Kalıbı)

Algoritma kümesinden hangi algoritmanın kullanılacağını çalışma zamanında belirleyen tasarım kalıbıdır. Algoritma kümesindeki her bir algoritma birbirleri yerine kullanılabilir.

Ne Zaman Kullanmalıyız

  • Bir işi yapabilecek birden fazla algoritma varsa
  • Nesnelerin çalışma zamanında algoritmalara göre davranışlarını değiştirmek istiyorsak
  • Yapılmak istenen bir işi birden fazla yöntemle yapmak istiyorsak
  • If-else, switch gibi yapılarla kod karmaşıklığının önüne geçmek istiyorsak

Bu sayede esnek bir yapı sağlanmış olur. Yani sınıfta değişiklik yapmaya gerek olmadan özellikler extend edilebilir. Buda bize Open/Closed Princible hatırlatır.

Kullanım sıklığı

  • Orta Yüksek -> %80

UML Diagram

  • Context ve Strategy arasında Aggregation söz konusu. Bu olmalı ki Context belirlenen Strategy referansı üzerinden işlemini yapması gerekiyor.
  • Strategy: Interface/Abstract yapıda olabilir. Birden fazla algoritmalar için çatı görevini üstlenir.
  • ConcreteStrategy: İlgili Algoritmayı gerçekleştiren somut sınıflarımız.
  • Context: Strategy sınıfı ile arasında loosley-coupled ilişkisi olan sınıfımız

Strategy Pattern Kod Örneği

Template Method Pattern

Bir işlem için gerekli olan adımları soyutlayarak bir şablon metot ile algoritmaların nasıl çalışacağını belirleyen ve kalıtım ile alt sınıfların bu soyut adımları kendi bünyesinde uygulayarak algoritmaların çalışmasını sağlayan tasarım kalıbıdır. Template Method ile Strategy arasında güçlü benzerlik vardır. İkisi de genişletilebilirdik ve özelleştirme için tasarlanmıştır.

Ne Zaman Kullanmalıyız

  • Sıralı işlemlerden bazılarını soyutlamak istiyorsak
  • Algoritmaların değişen kısımlarını altı sınıfların ele almasını istiyorsak
  • Algoritma iskeletinde yapılacak olan değişikliklerin merkezi bir yer yerden yapılmasını istiyorsak

Kullanım Sıklığı

  • Medium -> %60

UML Diagram

  • AbstractClass: Soyut adımları belirlediğimiz ve bu adımlar için Template Method barındıran sınıfımız.
  • ConcreteClass: Soyut metotları uygulayacak somut sınıflarımız.

Template Method Pattern Kod Örneği

Visitor Pattern

Hiyerarşik yapıda ve farklı tipte olan nesnelerin mevcut yapılarını değiştirmeden işlem yapabilmek amacıyla kullanılır. İşlemi ziyaretçi (visitor) nesneler yapar. Ziyaretçi nesneler sayesinde yeni metotlar tanımlanabilir ve ilgili nesneler bu ziyaretçi nesneye parametre olarak aktarılıp işlem yapılır.

Ne Zaman Kullanmalıyız

  • Yapıya sıklıkla yeni işlemler eklemek istiyorsak
  • Mevcut yapıyı değiştirmeden ek işlemler yapmak istiyorsak
  • Yapılacak işlemleri merkezi bir nesneden yönetmek istiyorsak

Kullanım Sıklığı

  • Düşük -> %20

UML Diagram

  • Visitor: Abstract/Interface yapıda tasarlanabilir. Ziyaret edilecek nesnelerin metot gövdelerini barındırır.
  • ConcreteVisitor: Ziyaret edilecek nesneler ile işlemlerin ele alındığı sınıf.
  • Element: Ziyaret edilecek sınıf.
  • ConcreteElement: Ziyaretçi nesnemiz ile haberleşen sınıf.

Visitor Pattern Kod Örneği

Memento Pattern

Nesnelerin hallerini tutan ve farklı nesne halleri arasında geçiş yapmayı sağlayan ve bir nesneyi önceki duruma geri yükleme kabiliyeti kazandıran tasarım kalıbıdır.

Ne Zaman Kullanmalıyız

  • Nesne durumunun anlık görüntüsü (snapshot) almak istiyorsak
  • Nesnenin bir önceki durumuna geri yüklenebilmesini istiyorsak

Kullanım Sıklığı

  • Düşük -> %20

UML Diagram

  • Originator: Sınıfımızın eski ve yeni hallerini tutacak olan nesne.
  • Memento: Originator sınıfındaki istediğimiz alanları tutacak olan nesne.
  • Caretaker: Geri dönüş adımlarını Memento tipinde tutan nesne.

Memento Pattern Kod Örneği

Bir yazının sonuna daha geldik. Behavioral Design Patterns hakkında elde ettiğim bilgiyi paylaşmaya çalıştım. Umarım faydalı olmuştur.

Sağlıkla kalın!

--

--