Design Patterns Nedir? (Gerçek Hayat Örnekleriyle)

Tuğba Aktürk
11 min readJan 5, 2024

Yazılım tasarımında yaygın olarak ortaya çıkan sorunlara tipik çözümlerdir. Kodunuzda yinelenen bir tasarım sorununu çözmek için özelleştirebileceğiniz önceden hazırlanmış planlar gibidirler. Kullanıma hazır fonksiyonlar veya kütüphanelerde olduğu gibi öylece bir kalıp bulup onu programımıza kopyalayamayız. Kalıplar belirli bir kod parçası değil, belirli bir sorunu çözmeye yönelik genel bir kavramdır.

Design Pattern’ların Sınıflandırılması

  1. Creational Patterns
  2. Structural Patterns
  3. Behavioral patterns

Creational Patterns

Yazılım sistemindeki nesnelerin yaratılışı hakkında yol gösterirler.

1. Factory Method

Bir üst sınıfta nesneler oluşturmak için bir arayüz sağlayan, ancak alt sınıfların oluşturulacak nesnelerin türünü değiştirmesine izin veren yaratıcı bir tasarım modelidir.

Örneğin, bir lojistik yönetim uygulamamız var ve ilk sürümünde biz sadece kamyonlarla taşımayı gerçekleştiriyoruz. Dolayısıyla kodlarımızın çoğu truck sınıfı içerisinde bulunuyor. Daha sonra uygulamamız büyüdükçe deniz lojistiğini de dahil etmek istiyoruz ama kodumuzun çoğu truck sınıfına bağlıdır. Daha sonra uygulamaya başka bir ulaşım türü eklemek istersek tüm değişiklikleri yeniden yapmamız gerekecek. Bu duruma çözüm, doğrudan nesne oluşturma çağrılarını (operatörü kullanarak) özel bir fabrika yöntemine yapılan çağrılarla değiştirmektir.

2. Abstarct Factory

Somut sınıflarını belirtmeden ilgili nesnelerin ailelerini üretmenizi sağlayan yaratıcı bir tasarım modelidir.

Factory design pattern’de tek bir ürün ailesine ait tek bir arayüz mevcutken, abstract factory’de farklı ürün aileleri için farklı arayüzler mevcuttur.

Örneğin, bir mobilya mağazası simülatörümüz var. Sandalye, kanepe ve masadan oluşan bir ailemiz var. Bu ailenin modern, eski gibi varyantları olabilir. Programa yeni ürünler veya ürün aileleri eklerken mevcut kodu değiştirmek istemeyiz. Bu modelin önerdiği ilk şey, ürün ailesinin her bir farklı ürünü örneğin; sandalye, kanepe için arayüzleri açıkça beyan etmektir. Daha sonra tüm sandalye çeşitleri arayüzü uygulayabilir.

3. Builder

Karmaşık nesneleri adım adım oluşturmanıza olanak tanıyan yaratıcı bir tasarım modelidir. Model, aynı yapı kodunu kullanarak bir nesnenin farklı türlerini ve temsillerini üretmenize olanak tanır.

Bir nesne oluşturacağımızı düşünelim. Basit bir ev inşa etmek için dört duvar, zemin, kapı, pencere ve çatı inşa etmeniz gerekir. Peki ya arka bahçesi ya da ısıtma sistemli bir ev istiyorsak ne yapmalıyız? Temel sınıfı genişletebiliriz ama yeni bir parametre daha gelirse hiyerarşi daha da büyüyecektir. Bu model, nesne yapım kodunu kendi sınıfından çıkarmanızı ve onu builders adı verilen ayrı nesnelere taşımanızı önerir. Böylece tüm adımları aramanıza gerek olmayacak ve yalnızca bir nesnenin belirli bir konfigürasyonunu oluşturmak için gerekli olan adımlar çağırılabilecektir.

4. Prototype

Kodunuzu sınıflarına bağımlı hale getirmeden mevcut nesneleri kopyalamanıza olanak tanıyan yaratıcı bir tasarım modelidir.

Örneğin, bir savaş oyununda aynı askerden yüzlerce tane bulunurken bu askerlerin yalnızca kimlik numaraları farklıdır. Her defasında yeni asker nesnesi yaratmak yerine var olan asker nesneleri kopyalanır ve kimlik numaraları değiştirilir.

5. Singleton

Bir class’tan sadece bir instance yaratılmasını sağlar. Yani herhangi bir class’tan bir instance yaratılmak istendiğinde, eğer daha önce yaratılmış bir instance yoksa yeni yaratılır. Daha önce yaratılmış ise var olan instance kullanılır.

Örneğin, bir uygulamada genellikle bir veritabanı bağlantısı kullanılır ve bu bağlantının sadece bir kere oluşturulması, daha sonra bu örneğin paylaşılması istenir. Bu durumda bu kalıp kullanılabilir.

Structural Patterns

Yazılım sistemindeki nesnelerin birbirleriyle olan ilişkilerini gösteren kalıptır.

1. Adapter

Uyumsuz arayüzlere sahip nesnelerin işbirliği yapmasına olanak tanıyan yapısal bir tasarım modelidir.

Borsa izleme uygulamamız olduğunu düşünelim. Uygulama, hisse senedi verilerini birden fazla kaynaktan XML formatında indirir ve ardından kullanıcıya grafiklerle sunar. Mesela uygulama geliştirilmek istendi ama analiz kitaplığı sadece JSON biçimindeki verilerle çalışıyor. Kütüphane XML ile çalışacak şekilde değiştirilirse kodlar bozulabilir. Bunu çözmek için analiz kitaplığının her sınıfı için XML’den JSON’a bağdaştırıcı oluşturulur. Kütüphane yalnızca bu bağdaştırıcılar aracılığıyla iletişim kurar. Bağdaştırıcı bir çağrı aldığında gelen XML verilerini bir JSON yapısına çevirir ve analiz kütüphanesine iletir.

2. Bridge

Büyük bir sınıfı veya yakından ilişkili sınıflar kümesini, birbirinden bağımsız olarak geliştirilebilen iki ayrı hiyerarşiye (soyutlama ve uygulama) ayırmanıza olanak tanıyan yapısal bir tasarım modelidir.

Örneğin, bir çift alt sınıfa sahip geometrik sınıfımız var. Bu sınıfa renkleri de içerecek şekilde genişletmek istiyoruz ancak iki alt sınıfımız olduğundan dört sınıf kombinasyonu oluşturmak gerekecektir. Bu hiyerarşiye yeni şekil türleri ve renkler eklemek onu katlayarak büyütecektir. Bu model nesne kompozisyonuna geçiş yaparak bu sorunu çözmeye çalışır. Bunun anlamı, boyutlardan birini ayrı bir sınıf hiyerarşisine çıkarmaktır. Böylece orijinal sınıflar, tüm durum ve davranışlarını tek bir sınıf içinde bulundurmak yerine yeni hiyerarşinin bir nesnesine referans verecektir.

3. Composite

Nesneleri ağaç yapılarında birleştirmenize ve daha sonra bu yapılarla sanki ayrı nesnelermiş gibi çalışmanıza olanak tanıyan yapısal bir tasarım modelidir.

Örneğin, çoğu ülkenin orduları hiyerarşik olarak yapılandırılmıştır. Bir ordu çeşitli tümenlerden oluşur; bir tümen bir dizi tugaydır ve bir tugay, mangalara bölünebilen müfrezelerden oluşur. Son olarak, bir takım gerçek askerlerden oluşan küçük bir gruptur. Emirler hiyerarşinin en üstünde verilir ve her asker ne yapılması gerektiğini bilene kadar her seviyeye aktarılır.

4. Decorator

Nesnelere yeni davranışlar eklemenizi sağlayan, bu nesneleri davranışları içeren özel sarmalayıcı nesnelerin içine yerleştirerek sağlayan yapısal bir tasarım modelidir.

Mesela bir uygulamada herkesin bildirim almak istediği yer farklı olabilir. Hatta birden fazla yerden almak isteyebilir. Bildirim sınıfları yapılandırılabilir fakat bu seçenek arttıkça daha fazla sayı çıkacak ve bunların da yapılandırılması gerekecektir. Öncelikle e-posta bildirim davranışını temel Notifier sınıfın içine bırakılıp diğer tüm bildirim yöntemleri dekoratörlere dönüştürülebilir.

5. Facade

Bir kütüphaneye, bir çerçeveye veya herhangi bir diğer karmaşık sınıf kümesine basitleştirilmiş bir arayüz sağlayan yapısal bir tasarım modelidir. Yazacağımız bu arayüzde alt sınıflar Facade sınıfımızdan bağımsız da çalışabilmeliler. Facade sadece bir kullanım kolaylığı sağlayan arayüz olacaktır.

Örneğin, telefonla sipariş vermek için bir mağazayı aradığınızda, operatör mağazanın tüm hizmetlerine ve departmanlarına karşı cephenizdir. Operatör size sipariş sistemi, ödeme ağ geçitleri ve çeşitli teslimat hizmetleri için basit bir sesli arayüz sağlar.

6. Flyweight

Tüm verileri her nesnede tutmak yerine birden fazla nesne arasında ortak durum bölümlerini paylaştırarak mevcut RAM miktarına daha fazla nesne sığdırmanıza olanak tanıyan yapısal bir tasarım modelidir.

Örneğin, bir metin belgesindeki karakterlerin saklanması düşünülebilir. Bir metin belgesinde aynı karakterin birçok kez tekrar edebileceği durumlar vardır. Her karakter için ayrı bir nesne oluşturmak özellikle büyük belgelerde bellek kullanımını arttırabilir.

7. Proxy

Başka bir nesne için bir yedek veya yer tutucu sağlamanıza olanak tanıyan yapısal bir tasarım modelidir. Proxy, orijinal nesneye erişimi kontrol ederek, isteğin orijinal nesneye ulaşmasından önce veya sonra bir şeyler yapmanıza olanak tanır.

Çok büyük miktarda sistem kaynağı tüketen devasa bir nesnemiz olsun. Buna zaman zaman ihtiyacımız olabilir. Bu durumda nesnenin tüm istemcilerinin bazı ertelenmiş başlatma kodlarını yürütmesi gerekir. Bu da muhtemelen çok fazla kod kopyasına neden olacaktır. Çözüm olarak orijinal hizmet nesnesiyle aynı arabirime sahip yeni bir proxy sınıfı oluşturulur. Uygulamayı proxy nesnesini orijinal nesnenin tüm istemcilerine aktaracak şekilde güncellenir. Bir istemciden bir istek aldıktan sonra proxy gerçek bir hizmet nesnesi oluşturur ve tüm işi ona devreder.

Behavioral Patterns

Nesne davranışlarını takip eden kalıptır.

1. Chain of Responsibility

İstekleri bir işleyici zinciri boyunca aktarmanıza olanak tanıyan davranışsal bir tasarım modelidir. Bir istek alındığında, her işleyici ya isteği işlemeye ya da zincirdeki bir sonraki işleyiciye iletmeye karar verir.

Örnek olarak otomatik ürün makinelerine ait jeton slotları verilebilir. Her tip jeton için bir slot oluşturmak, aslında arka arkaya if blokları yazarak, gelen talebin anlaşılmaya çalışılmasına benzetilebilir. Bunun yerine makine üzerinde, her bir jetonu ele alan tek bir slot tasarlanır(Handler). Ürünü satın almak isteyen kişinin attığı jeton, verdiği komuta(Cola, çikolata vs istemek gibi) ve jetonun tipine göre, içeride uygun olan saklama alanına düşecektir. Sonrasında ise süreç, jetonun uygun olan saklama alanında değerlendirilerek istenilen ürünün teslim edilmesiyle tamamlanacaktır.

2. Command

Bir isteği, istekle ilgili tüm bilgileri içeren bağımsız bir nesneye dönüştüren davranışsal bir tasarım modelidir. Bu dönüşüm, istekleri bir yöntem bağımsız değişkeni olarak iletmenize, bir isteğin yürütülmesini geciktirmenize veya sıraya koymanıza ve geri alınamayan işlemleri desteklemenize olanak tanır.

Örneğin, bir restorana gelip masaya oturuyorsunuz. Garson yanınıza yaklaşıyor ve siparişinizi hızla alıp bir kağıda yazıyor. Garson mutfağa gider ve siparişi duvara yapıştırır. Bir süre sonra sipariş şefe ulaşır, şef de onu okur ve yemeği ona göre pişirir. Aşçı yemeği siparişle birlikte tepsiye yerleştirir. Garson tepsiyi bulur, her şeyin istediğiniz gibi olduğundan emin olmak için siparişi kontrol eder ve her şeyi masanıza getirir.

Kağıt siparişi bir komut görevi görür. Şef servis etmeye hazır olana kadar kuyrukta kalır. Sipariş, yemeği pişirmek için gereken tüm bilgileri içerir. Bu, şefin sipariş ayrıntılarını doğrudan sizden açıklığa kavuşturmak yerine hemen yemek pişirmeye başlamasını sağlar.

3. Iterator

Bir koleksiyonun öğelerini, temel temsilini (liste, yığın, ağaç vb.) açığa çıkarmadan geçmenize olanak tanıyan davranışsal bir tasarım modelidir.

Örneğin, birkaç günlüğüne Roma’yı ziyaret etmeyi ve onun tüm önemli turistik yerlerini ve ilgi çekici yerlerini ziyaret etmeyi planlıyorsunuz. Ancak oraya vardığınızda, Colosseum’u bile bulamadan daireler çizerek çok fazla zaman harcayabilirsiniz.

Öte yandan, akıllı telefonunuz için sanal bir rehber uygulaması satın alabilir ve bunu navigasyon için kullanabilirsiniz. Akıllı ve ucuzdur ve ilginç yerlerde istediğiniz kadar kalabilirsiniz.

Üçüncü bir alternatif ise gezi bütçenizin bir kısmını harcayıp şehri avucunun içi gibi bilen yerel bir rehber tutmanızdır. Rehber, turu beğenilerinize göre düzenleyebilir, size her atraksiyonu gösterebilir ve birçok heyecan verici hikaye anlatabilir. Bu daha da eğlenceli olacak; ama ne yazık ki aynı zamanda daha pahalı.

Tüm bu seçenekler (kafanızda doğan rastgele yönler, akıllı telefon gezgini veya insan rehberi), Roma’da bulunan geniş manzara ve turistik yerler koleksiyonu üzerinde yineleyici görevi görür.

4. Mediator

Nesneler arasındaki kaotik bağımlılıkları azaltmanıza olanak tanıyan davranışsal bir tasarım modelidir. Desen, nesneler arasındaki doğrudan iletişimi kısıtlar ve onları yalnızca aracı bir nesne aracılığıyla işbirliği yapmaya zorlar.

Örneğin, havaalanı kontrol alanına yaklaşan veya ayrılan uçak pilotları birbirleriyle doğrudan iletişim kurmuyor. Bunun yerine, uçak pistine yakın bir yerde yüksek bir kulede oturan bir hava trafik kontrolörüyle konuşuyorlar. Hava trafik kontrolörü olmasaydı, pilotların havaalanı yakınındaki her uçaktan haberdar olması ve düzinelerce pilottan oluşan bir komiteyle iniş önceliklerini tartışması gerekecekti. Bu muhtemelen uçak kazası istatistiklerini hızla yükseltirdi.

Kulenin tüm uçuşu kontrol etmesine gerek yok. Yalnızca terminal alanındaki kısıtlamaları uygulamak için mevcuttur çünkü oradaki ilgili aktörlerin sayısı bir pilot için çok fazla olabilir.

5. Memento

Uygulamanın ayrıntılarını açıklamadan bir nesnenin önceki durumunu kaydetmenize ve geri yüklemenize olanak tanıyan davranışsal bir tasarım modelidir.

Örneğin, bir metin düzenleyici uygulaması içerisinde bir kullanıcı bir paragrafı düzenler ve birkaç kelimeyi siler. Bu noktada uygulama, bu durumu temsil eden bir “Memento” nesnesi oluşturabilir ve bu nesneyi bir geri alma geçmişi içinde saklayabilir. Kullanıcı “Undo” işlemini gerçekleştirdiğinde, uygulama en son geri alma geçmişindeki “Memento” nesnesini kullanarak silinen kelimeleri geri getirebilir.

6. Observer

Birden çok nesneyi, gözlemledikleri nesnenin başına gelen herhangi bir olay hakkında bilgilendirmek için bir abonelik mekanizması tanımlamanıza olanak tanıyan davranışsal bir tasarım modelidir.

Örneğin, bir gazete veya dergiye abone olursanız, bir sonraki sayının mevcut olup olmadığını kontrol etmek için artık mağazaya gitmenize gerek yoktur. Bunun yerine, yayıncı yeni sayıları yayınlandıktan hemen sonra veya hatta önceden doğrudan posta kutunuza gönderir.

Yayıncı, abonelerin bir listesini tutar ve hangi dergilerle ilgilendiklerini bilir. Aboneler, yayıncının kendilerine yeni dergi sayıları göndermesini engellemek istediklerinde listeden istedikleri zaman ayrılabilirler.

7. State

Bir nesnenin iç durumu değiştiğinde davranışını değiştirmesine olanak tanıyan davranışsal bir tasarım modelidir. Sanki nesne sınıfını değiştirmiş gibi görünüyor.

Örneğin, akıllı telefonunuzdaki düğmeler ve anahtarlar, cihazın mevcut durumuna bağlı olarak farklı davranır:

  • Telefonun kilidi açıkken düğmelere basmak çeşitli işlevlerin yürütülmesine yol açar.
  • Telefon kilitliyken herhangi bir düğmeye basıldığında kilit açma ekranı açılır.
  • Telefonun şarjı azaldığında herhangi bir tuşa basıldığında şarj ekranı görüntülenir.

8. Strategy

Bir algoritma ailesi tanımlamanıza, her birini ayrı bir sınıfa koymanıza ve nesnelerini birbirinin yerine kullanılabilir hale getirmenize olanak tanıyan davranışsal bir tasarım modelidir.

Örneğin, havaalanına gitmeniz gerektiğini düşünün. Otobüse binebilir, taksi çağırabilir veya bisikletinize binebilirsiniz. Bunlar sizin ulaşım stratejilerinizdir. Bütçe veya zaman kısıtlaması gibi faktörlere bağlı olarak stratejilerden birini seçebilirsiniz.

9. Template Method

Üst sınıftaki bir algoritmanın iskeletini tanımlayan ancak alt sınıfların, yapısını değiştirmeden algoritmanın belirli adımlarını geçersiz kılmasına izin veren davranışsal bir tasarım modelidir.

Örneğin, toplu konut inşaatlarında şablon yöntemi yaklaşımı kullanılabilir. Standart bir ev inşa etmeye yönelik mimari plan, potansiyel sahibinin ortaya çıkan evin bazı ayrıntılarını ayarlamasına olanak tanıyan birkaç uzatma noktası içerebilir. Temelin döşenmesi, çerçeveleme, duvarların inşa edilmesi, su ve elektrik için sıhhi tesisat ve kabloların döşenmesi gibi her inşaat adımı, ortaya çıkan evi diğerlerinden biraz farklı kılmak için biraz değiştirilebilir.

10. Visitor

Algoritmaları üzerinde çalıştıkları nesnelerden ayırmanıza olanak tanıyan davranışsal bir tasarım modelidir.

Yeni müşteriler kazanmaya hevesli deneyimli bir sigorta acentesini hayal edin. Mahalledeki her binayı gezebiliyor, karşılaştığı herkese sigorta satmaya çalışıyor. Binayı işgal eden kuruluşun türüne bağlı olarak özel sigorta poliçeleri sunabilir:

  • Eğer bu bir konut binasıysa sağlık sigortası satıyor.
  • Eğer bankaysa hırsızlık sigortası satıyor.
  • Kahvehane ise yangın ve su baskını sigortası satıyor.

İlk yazımın sonuna geldik. Sizlere kısaca design patterns’lardan bahsetmek istedim. İyi çalışmalar dilerim..

Bana ulaşabilirsiniz: LinkedIn

--

--