Observer Design Pattern in Swift: Real-World Examples and Implementation

Abdullah Arslan
5 min readApr 23, 2024

--

Merhaba arkadaşlar,

Daha önce Strategy Design Pattern’ını ele almıştık, bugün de Observer Design Pattern’ına bir göz atacağız.

Doslar hayat, beklenmedik anlarda sürprizlerle doludur; bazen bir kapının ardında sizi bekleyen fırsatlar, bazen de en umutsuz anınızda gelen umut ışığı. Observer tasarım deseni de bu doğaya benzer bir şekilde çalışır; bir nesnenin durumu değiştiğinde, diğer nesneler otomatik olarak haberdar edilir ve gerektiğinde tepki verirler. Bu durum, hayatta her an bir mucizeye hazır olmanız gerektiğini hatırlatır. Her şeyin nasıl gelişeceğini beklemek yerine, olacakları gözlemlemeli ve buna göre hareket etmelisiniz. Unutmayın, bazen en büyük mucizeler, en küçük gözlemlerle başlar. Evet biraz boş yaptıktan sonra konumuza tekrar dönelim 😋

Bir uygulama geliştirdiniz ve herkesi yeni güncellemelerden haberdar etmek istiyorsunuz, ancak kimse sadece bildirimleri kontrol etmek için uygulamanızı sürekli açmak istemez, değil mi? İşte tam burada Observer Tasarım Deseni devreye giriyor! Bu desen, uygulamanızdaki değişiklikleri takip eden ve kullanıcıları bilgilendiren bir mekanizma sunar. Şimdi, bu desenin nasıl çalıştığını ve nasıl uygulanacağını keşfetmeye hazır mısınız?

“Her şeyi beklemek, hiçbir şeyi beklememek kadar kötüdür.” — Publilius Syrus

Observer Design Pattern, bir nesnenin durumundaki değişiklikleri takip eden ve bu değişikliklerden etkilenen diğer nesneleri bilgilendiren bir tasarım desenidir. Bu desen, bir nesnenin durumu değiştiğinde bağımlı nesnelerin otomatik olarak güncellenmesini sağlar.

Observer Design Pattern’ı oluşturan temel unsurlar şunlardır:

  1. Subject (Özne): Gözlemcilerin kaydedildiği, kaldırıldığı ve güncellendiği nesnedir. Subject, gözlemcilere bildirim gönderir ve onları güncel durum hakkında bilgilendirir.
  2. Observer (Gözlemci): Bir arayüz veya sınıf olarak tanımlanan gözlemciler, bir konuya bağlı olarak güncellemeleri alacak nesnelerdir. Observer, güncelleme aldığında tepki gösteren metodları içerir.
  3. Concrete Subject (Somut Özne): Subject arayüzünü veya sınıfını uygular ve gözlemcileri kaydeder, kaldırır ve günceller. Durum değiştiğinde gözlemcilere bildirim gönderir.
  4. Concrete Observer (Somut Gözlemci): Observer arayüzünü veya sınıfını uygular ve bir özneye kaydolur. Özne durumu değiştiğinde güncelleme alır ve uygun şekilde tepki verir.

Örneğin, bir müşteri siparişi verdiğinde, sipariş durumu değişebilir ve bu durum müşteriye bildirilmelidir. Bu durumu Observer Design Pattern’ı kullanarak gerçekleştirebiliriz. Kod üzerinden daha iyi anlayacağınızı düşünüyorum.

“Dünya bir ev olsaydi mutfagi Gaziantep olurdu”
// Observer protokolü, Kullanıcıların sınıfında bulunan bu metodu tetikleyeceğiz.
protocol Observer: AnyObject {

func update(status: OrderStatus)
}


// Observable (Gözlenebilir) protokolü, Bunu alan sınıfla Observerlara bildirimde bulunabilecek..
protocol Observable {
var observers: [Observer] { get set }

func addObserver(_ observer: Observer)
func removeObserver(_ observer: Observer)
func updateStatus(for customer: Customer, to status: OrderStatus)
}

Arkadaşlar protocoller kullandığınız zaman içerisinde yazdığınız özellikleri protocolleri verdiğiniz sınıflar kullanmak zorundasınız. Java’da veya diğer dillerde bu yapıya “interface” deniliyor.

Şimdi ise yukarıda tanımladığımız kuralları sınıflarımıza ekleyelim.

// Burda ise kendisine abone olan kişilere bildirimde bulunacak sınıfımız.
// Örneğin ArslanYemekCom firmasında yemeğinin durumunu görmek isteyen kişiler.
class Order: Observable {

// Bu liste, bu servisten durum bildirimleri alacak olan kişileri içerir.
var observers: [Observer] = []

// Observer'ları listeye ekler.
func addObserver(_ observer: Observer) {
observers.append(observer)
}

// Observer'ları listeden çıkarır.
func removeObserver(_ observer: Observer) {
observers = observers.filter { $0 !== observer }
}

// Burası biraz karışık gelebilir.
// Bu fonksiyon da, belirli bir müşteriye ait olan `Observer`ı buluyoruz ve
// onun `update` metodunu çağırarak durumu güncelliyoruz..
func updateStatus(for customer: Customer, to status: OrderStatus) {
// İlgili müşterinin bulunduğu index'i buluyoruz.
if let index = observers.firstIndex(where: { ($0 as? Customer)?.name == customer.name }) {
// Bulunan müşteriye ait Observer'ı alıyoruz.
let customer = observers[index] as! Customer
// Observer'ın `update` metodunu çağırarak durumu güncelliyoruz.
customer.update(status: status)
}
}

}

Şimdi bu bildirimleri alan Customer sınıfımızı tanımlayalım.

// Bildirimleri göndereceğimiz. Abonelerimizi tanımlıyoruz.
class Customer: Observer {
var name: String

init(name: String) {
self.name = name
}

func update(status: OrderStatus) {

print("\(name) siparişinizin durumu \(status) olarak güncellendi.")

}
}

Şimdi sınıflarımızı tanımlayalım.

// Bildirimde bulunacak sınıfımız.
let arslanYemekCom = Order()

// Sipariş veren birinci müşterimiz.
let customer1 = Customer(name: "Abdullah")

// Sipariş veren ikinci müşterimiz.
let customer2 = Customer(name: "Mehmet")

arslanYemekCom.addObserver(customer1)

arslanYemekCom.addObserver(customer2)

Şimdi ise güncellemek istediğimiz observerımıza bildirimde bulunalım.

arslanYemekCom.updateStatus(for: customer2, to: .onTheWay)

// Mehmet siparişinizin durumu onTheWay olarak güncellendi.
arslanYemekCom.updateStatus(for: customer1, to: .preparing)
// Abdullah siparişinizin durumu preparing olarak güncellendi.

Bu örneği konun daha iyi anlaşılması için hazırladım. Bu sistemi tabiki çok daha farklı bir şekilde kurabaliriz. Ben kendi anladığım şekilde açıklamaya çalıştım.

Isterseniz şimdi de farklı örneklerle bu sistemin kullanımını pekiştirelim.

  1. Abonelik Hizmetleri: Bir kullanıcı belirli bir içeriğe abone olduğunda (örneğin, bir dergi veya bir video akışı), içerik güncellendiğinde otomatik olarak haberdar edilir. Kullanıcı, abonelikten vazgeçene kadar güncellemeleri alır.
  2. Sosyal Medya Bildirimleri: Bir kullanıcı belirli bir kişiyi veya sayfayı takip ettiğinde, takip ettiği kişi veya sayfa yeni bir şey paylaştığında kullanıcı otomatik olarak bildirim alır.
  3. Hava Durumu Bildirimleri: Bir hava durumu uygulamasında, kullanıcı belirli bir konumu takip ettiğinde, hava durumu güncellendiğinde kullanıcıya otomatik olarak bildirim gönderilir.
  4. E-Ticaret Sipariş Takibi: Bir müşteri bir ürün satın aldığında, siparişin durumu (hazırlanıyor, kargoya verildi, teslim edildi vb.) güncellendiğinde müşteriye otomatik olarak bildirim gönderilir.
“Head First Design Patterns” by Eric Freeman, Elisabeth Robson: Resimde gösterilen nesnelerin ortak bir fonksiyonunu çalıştırarak, bildirimde bulunmuş oluyoruz.

Bu örneklerde olduğu gibi, Observer deseni, bir nesnenin durum değişikliklerini diğer nesnelere bildirmek ve bu nesnelerin bu değişikliklere tepki vermesini sağlamak için kullanılabilir. Bu sayede, bir nesnenin durumu değiştiğinde ilgili diğer nesnelerin otomatik olarak güncellenmesi ve senkronize olması sağlanır.

Ayrıca swift dilindeki Combine framework’ü ve NotificationCenter gibi yapılar, Observer tasarım desenini daha kolay ve etkili bir şekilde kullanmamızı sağlar. Combine, Swift’te yaygın olarak kullanılan bir reactive programming framework’üdür ve Observable ve Observer yapılarını kullanarak veri akışlarını yönetmemizi sağlar. NotificationCenter ise, uygulama içindeki herhangi bir yerden bildirimler göndermemizi ve dinlememizi sağlar, bu da Observer desenine benzer bir mekanizma sunar.

Bu yapıları kullanarak, bir nesnenin durumu değiştiğinde veya bir olay gerçekleştiğinde diğer nesneleri veya bileşenleri otomatik olarak güncelleyebiliriz. Combine ve NotificationCenter gibi yapılar, kodun daha temiz, daha okunabilir ve daha bakımı kolay olmasını sağlar. Bu yapıları kullanarak, Observer desenini uygulamak için daha az kod yazmamızı ve daha az hata yapmamızı sağlarlar. Dolayısıyla, Swift’te geliştirme yaparken bu yapıları kullanmayı tercih etmek, Observer desenini kullanmayı daha kolay ve verimli hale getirebilir. Hoşça kalın! Yazılım maceranızda başarılar dilerim.

Yararlandığım Kaynaklar

--

--

Abdullah Arslan

I'm a lifelong learner, always seeking knowledge in areas that interest me. I strive to create an infinite loop of learning, experiencing, and sharing.