JavaScript’te Gözlemci Modelinin Gücü – JSManifest

JavaScript'te Gözlemci Modelinin Gücü – JSManifest

Bu yazıda, üzerinden geçeceğiz Gözlemci Modeli ve JavaScript ile uygulamak, böylece özellikle kavramı anlamakta zorluk çekiyorsanız, daha iyi anlayabilmenizi umuyoruz.

Gözlemci modeli, ayrıştırılmış sistemleri tasarlamak için en iyi uygulamalardan biri olmaya devam ediyor ve herhangi bir JavaScript geliştiricisinin kullanması için önemli bir araç olmalıdır.

Gözlemci modeli, öznelerin (sadece nesneler yöntemlerle) ” olan gözlemcilerin bir listesini tutun.kayıtlı” yaklaşan mesajlardan haberdar olmak için. Bağlı oldukları konudan bir şey hakkında bir bildirim olayı aldıklarında, onlardan ne aldıklarına bağlı olarak bu fırsatları faydalı bir şeyler yapmak için kullanabilirler.

Kalıp, en son durum değişiklikleri hakkında aynı anda aynı anda bildirim almak için birden çok nesneye ihtiyaç duyduğunuz durumlarda kullanışlıdır. Böylece, sıkı bir şekilde birleştirilmiş sınıflara sahip olmanın aksine, uygulamanız genelinde tutarlılığı korumak için birden çok nesneye ihtiyaç duyduğunuzda bu kalıbın gücü ortaya çıkar. Bununla birlikte, aynı anda tutarlı kalmak için birbiriyle doğrudan ilişkili olmayan birkaç nesneye sahip olmak bile mümkündür.

Gözlemciler bağlandıktan sonra kendilerini çıkarabilirler, bu nedenle bir gözlemciyi ve bir sonrakini kabul etme ve devre dışı bırakma ve tam tersi için biraz esneklik bile vardır. Tüm bu işlevleri bir araya getirdiğinizde, dinamik ilişkiler sağlam işlevsellik oluşturan denekler ve gözlemciler arasında.

Konsept şöyle devam ediyor:

Bir gözlemci, bir öznenin durumu hakkında endişelendiğinde ve “gözlemek” yaklaşan durum güncellemeleri, yaklaşan bilgileri almak için kayıt olabilir veya kendilerini onlara ekleyebilirler. Daha sonra, bir şey değiştiğinde, bu gözlemciler bundan sonraki güncellemeler de dahil olmak üzere bundan haberdar olabilecekler. Bu, özne, bazı yayın yöntemlerini kullanarak bağlı gözlemcisine/gözlemcilerine bildirim mesajları gönderdiğinde yapılır. Bu bildirim mesajlarının her biri, onları alan bir veya daha fazla gözlemci için faydalı veriler içerebilir. Bildirim mesajlarının gönderilme şekli genellikle bazı bildirmek kendi gözlemciler listesinde dolaşma yöntemi ve her döngünün içinde gözlemcinin Güncelleme yöntem. Gözlemci artık özneyle ilişkilendirilmek istemediğinde ayrılabilir.

İşte bu kalıbı oluşturan tüm ortak katılımcıların yer aldığı kısa ve kesin bir tablo:

İsim Tanım
Ders Gözlemcileri korur. Gözlemcilerin eklenmesini veya çıkarılmasını önerebilir
Gözlemci Bir Konunun durum değişikliklerinden haberdar edilmesi gereken nesneler için bir güncelleme arayüzü sağlar
BetonKonu Durum değişiklikleri hakkında Gözlemcilere bildirimler yayınlar, ConcreteObservers’ın durumunu saklar
BetonGözlemcisi ConcreteSubject’e bir referans depolar, Observer’ın durumun Özne’ninkiyle tutarlı olmasını sağlamak için bir güncelleme arayüzü uygular.

Şimdi devam edelim ve bunun kodda nasıl görünebileceğini görelim.

Yapacağımız ilk şey, gözlemcilerini yönetmek için bir arayüze sahip olacak konuyu oluşturmaya başlamak. Bunu yapmak için, aslında kurucuyu adı verilen ayrı bir fonksiyon üzerinde tanımlayacağız. ObserversList:

function ObserversList() {
  this.observers = []
}

ObserversList.prototype.add = function(observer) {
  return this.observers.push(observer)
}

ObserversList.prototype.get = function(index) {
  if (typeof index !== number) {
    console.warn('the index passed in to getObserver is not a number')
    return
  }
  return this.observers[index]
}

ObserversList.prototype.removeAt = function(index) {
  this.observers.splice(index, 1)
}

ObserversList.prototype.count = function() {
  return this.observers.length
}

ObserversList.prototype.indexOf = function(observer, startIndex = 0) {
  let currentIndex = startIndex

  while (currentIndex < this.observers.length) {
    if (this.observers[currentIndex] === observer) {
      return currentIndex
    }
    currentIndex++
  }

  return -1
}

ObserversList.prototype.notifyAll = function(data) {
  const totalObservers = this.observers.length
  for (let index = 0; index < totalObservers; index++) {
    this.observers(index).update(data)
  }
}

Ve sonra bu arayüzü doğrudan bir öznenin özelliğine ekleriz:

function Subject() {
  this.observers = new ObserversList()
}

Prototip yöntemleri doğrudan konuyla ilgili olarak tanımlayabilirdik, ancak bunu yapmamamızın nedeni, deneklerin genellikle gerçek dünya kullanım durumunda sadece gözlemci arayüzünü devralması gereken bir şeyin keyfi örnekleri olacak ve muhtemelen işlevselliğini genişletmek veya etraflarında sarmalayıcılar oluşturmak.

Şimdi devam edeceğiz ve tanımlayacağız Gözlemci:

function Observer() {
  this.update = function() {}
}

Farklı nesneler miras aldığında Gözlemcigenellikle olan şey, update (veya bazı güncelleyici) işlevi, aradıkları bazı verilerle ilgilenir.

Bunun nedeni, özne onu çağırdığında notifyAll yönteminde, her döngüde gözlemcinin güncelleyici işlevi kullanılır.

Bunu yukarıdaki eylemde görebilirsiniz:

ObserversList.prototype.notifyAll = function(data) {
  const totalObservers = this.observers.length
  for (let index = 0; index < totalObservers; index++) {
    
    this.observers(index).update(data)
  }
}

Gerçek Dünya Örneği

Şimdi gerçek dünyadan bir örneğe geçelim.

bir işlem yaptığımızı varsayalım. DMV yerde Alhambra. Gözlemci desenini kullanarak bilet çağırma sistemini uygulayacağız.

DMV’deki tipik bir bilet arama sisteminde, insanlara bekleme listesine alınırlarsa genellikle bir bilet numarası verilir ve numaraları aranana kadar beklerler.

Bilet numaraları kendilerine verilmeden hemen önce, DMV onlara teslim etmeden önce bir gişenin mevcut olup olmadığını kontrol eder. Uygun gişe yoksa, kendilerine atanan bilet numarası ile bekleme listesine alınırlar.

Bir kişi stanttaki seansını tamamladığında, o gün için işi bitmiş gibi davranalım. Bu, bilet numaralarının artık kullanılmadığı ve daha sonra tekrar kullanılabildiği zamandır. Örneğimizde, bekleme listesine alınacak başka birine atanmak üzere bilet numaralarını hemen kullanılabilir olarak işaretleyeceğiz.

Yapmamız gereken ilk şey, DMV yapıcı:

function DMV(maxTicketsToProcess = 5) {
  this.ticketsFree = new Array(40).fill(null).map((_, index) => index + 1)
  this.ticketsProcessing = []
  this.maxTicketsToProcess = maxTicketsToProcess
  this.waitingList = new WaitingList()
}

Örneğimizde, DMV bu ders çünkü bir kişi listesini ve bilet numaralarını yönetecek.

biz ayarladık maxTicketsToProcess parametre çünkü onsuz, bekleme listesi her zaman boş olacak çünkü bilmenin bir yolu olmayacak ne zaman bir kişinin bekleme listesine alınması uygundur. Ne zaman maxTicketsToProcess ulaşıldığında, bir bilet numarası ile insanları bekleme listesine almaya başlayacağız. hala bilet varsa this.ticketsFree.

Şimdi baktığımızda DMV yapıcı, atama yapıyor this.waitingList Birlikte WaitingList misal. O WaitingList temelde ObserversList insan listesini yönetmek için neredeyse aynı bir arayüz sağladığı için:

function WaitingList() {
  this.waitingList = []
}

WaitingList.prototype.add = function(person) {
  this.waitingList.push(person)
}

WaitingList.prototype.removeAt = function(index) {
  this.waitingList.splice(index, 1)
}

WaitingList.prototype.get = function(index) {
  return this.waitingList[index]
}

WaitingList.prototype.count = function() {
  return this.waitingList.length
}

WaitingList.prototype.indexOf = function(ticketNum, startIndex) {
  let currentIndex = startIndex

  while (currentIndex < this.waitingList.length) {
    const person = this.waitingList[currentIndex]
    if (person.ticketNum === ticketNum) {
      return currentIndex
    }
    currentIndex++
  }
  return -1
}

WaitingList.prototype.broadcastNext = function(ticketNum) {
  const self = this
  this.waitingList.forEach(function(person) {
    person.notifyTicket(ticketNum, function accept() {
      const index = self.waitingList.indexOf(person)
      self.waitingList.removeAt(index)
      delete person.processing
      delete person.ticketNum
      self.ticketsProcessing.push(ticketNum)
    })
  })
}

broadcastNext bizim eşdeğerdir notifyAll yöntemden ObserversList örnek. aramak yerine .update yine de diyoruz .notifyTicket bu, kişi örneğinde (birazdan göreceğimiz) tanımlanır ve bir accept ikinci argüman olarak geri arama işlevi görür çünkü bu, bir kişi bilet numarasına baktığında, kendisine atanan numaranın arandığını fark ettiğinde ve kabinine gittiğinde gerçek hayat senaryosunu simüle edecektir.

Bir tanımlayalım Person her kişi için somutlaştırılacak kurucu:

function Person(name) {
  this.name = name
}

yöntem olduğunu fark etmişsinizdir. notifyTicket burada kullandığımız için eksik:

person.notifyTicket(ticketNum, function accept() {

Bu iyi, çünkü bir bekleme listesinin arayüzünü genel bir listeyle karıştırmak istemiyoruz. People bir.

Yani, bir oluşturacağız WaitingListPerson özellikle insanlar için kendi arayüzünü içerecek yapıcı bekleme listesinde çünkü bu işlevlerin kişi dışarı çıkarıldıktan sonra hiçbir faydası olmayacağını biliyoruz. Bu yüzden işleri düzenli ve basit tutuyoruz.

Örnekleri genişletme yöntemimiz Person adlı bir yardımcı program aracılığıyla extend:

function extend(target, extensions) {
  for (let ext in extensions) {
    target[ext] = extensions[ext]
  }
}

Ve işte tanımı WaitingListPerson:

function WaitingListPerson(ticketNum) {
  this.ticketNum = ticketNum

  this.notifyTicket = function(num, accept) {
    if (this.ticketNum === num) {
      accept()
    }
  }
}

Harika! Yapacağımız son şey, nihayet yöntemleri uygulamaktır. DMV böylece kişi ekleyebilir/kaldırabilir, bilet numaralarını yönetebilir vb.

function DMV(maxTicketsToProcess = 5) {
  this.ticketsFree = new Array(40).fill(null).map((_, index) => index + 1)
  this.ticketsProcessing = []
  this.maxTicketsToProcess = maxTicketsToProcess

  this.waitingList = new WaitingList()
}




DMV.prototype.add = function(person) {
  if (this.ticketsProcessing.length < this.maxTicketsToProcess) {
    const ticketNum = this.ticketsFree.shift()
    console.log(`Taking next ticket #${ticketNum}`)
    this.processNext(person, ticketNum)
  } else {
    this.addToWaitingList(person)
  }
}



DMV.prototype.processNext = function(person, ticketNum) {
  person.processing = true
  if (ticketNum !== undefined) {
    person.ticketNum = ticketNum
    this.ticketsProcessing.push(ticketNum)
  }
}



DMV.prototype.addToWaitingList = function(person) {
  const ticketNum = this.ticketsFree.splice(0, 1)[0]
  extend(person, new WaitingListPerson(ticketNum))
  this.waitingList.add(person)
}



DMV.prototype.complete = function(person) {
  const index = this.ticketsProcessing.indexOf(person.ticketNum)
  this.ticketsProcessing.splice(index, 1)[0]
  this.ticketsFree.push(person.ticketNum)
  delete person.ticketNum
  delete person.processing
  if (this.waitingList.count() > 0) {
    this.waitingList.broadcastNext(this.ticketsFree.shift())
  }
}

Artık gözlemci modeliyle desteklenen yeterli bir DMV biletleme sistemimiz var!

Bunu kullanımda görmeyi deneyelim:

const alhambraDmv = new DMV()

const michael = new Person('michael')
const ellis = new Person('ellis')
const joe = new Person('joe')
const jenny = new Person('jenny')
const clarissa = new Person('clarissa')
const bob = new Person('bob')
const lisa = new Person('lisa')
const crystal = new Person('crystal')

alhambraDmv.add(michael)
alhambraDmv.add(ellis)
alhambraDmv.add(joe)
alhambraDmv.add(jenny)
alhambraDmv.add(clarissa)
alhambraDmv.add(bob)
alhambraDmv.add(lisa)
alhambraDmv.add(crystal)

const ticketsFree = alhambraDmv.ticketsFree
const ticketsProcessing = alhambraDmv.ticketsProcessing

console.log(`waitingNum: ${alhambraDmv.waitingList.count()}`)
console.log(
  `ticketsFree: ${ticketsFree.length ? ticketsFree.map((s) => s) : 0}`,
)
console.log(`ticketsProcessing: ${ticketsProcessing.map((s) => s)}`)

console.log(michael)
console.log(ellis)
console.log(joe)
console.log(jenny)
console.log(clarissa)
console.log(bob)
console.log(lisa)
console.log(crystal)

alhambraDmv.complete(joe)

console.log(`waitingNum: ${alhambraDmv.waitingList.count()}`)
console.log(
  `ticketsFree: ${ticketsFree.length ? ticketsFree.map((s) => s) : 0}`,
)
console.log(`ticketsProcessing: ${ticketsProcessing.map((s) => s)}`)

alhambraDmv.complete(clarissa)

console.log(michael)
console.log(ellis)
console.log(joe)
console.log(jenny)
console.log(clarissa)
console.log(bob)
console.log(lisa)
console.log(crystal)

Şimdi, gözlemci modelinin uygulamanızı ne kadar ileri götürebileceğini gördük. İşlevsel bir DMV bilet arama sistemi oluşturmak için bundan faydalandık! Arkanıza yaslanın!

Çözüm

Ve bu yazının sonu burada bitiyor! Umarım bunu değerli bulmuşsunuzdur ve gelecekte daha fazlasını ararsınız!

Bir cevap yazın

E-posta hesabınız yayımlanmayacak.