Javscript

JavaScript’te Ziyaretçi Tasarım Modelinin Gücü – JSManifest

Web uygulamaları geliştirirken, değer açısından çok ödüllendirici olan güçlü bir strateji, Ziyaretçi Tasarım Modelidir. Bu gönderi JavaScript’teki Ziyaretçi Kalıbını gözden geçirecek ve her JavaScript geliştiricisinin Ziyaretçiyi kullanırken bilmesi gereken bazı önemli kavram ve teknikleri ortadan kaldıracaktır.

Deneyimlerime göre Ziyaretçi, başlarken hem kodda hem de görsel açıdan anlaşılması en karmaşık kalıplardan biridir, ancak bir kez alıştığınızda aslında o kadar da kötü değildir.

Çoğunlukla kütüphanelerde veya çerçevelerde uygulanan ziyaretçiler buluyoruz, bu nedenle çok sayıda kitaplık veya çerçeve kullanmadıysanız, henüz ziyaretçilerle çalışmamış olabilirsiniz. Kütüphane yazarları genişletilebilirlik aradığında genellikle yararlıdırlar.

İki ana katılımcı var gereklidir ziyaretçi kalıbını tamamlamak için (müşteri kodu dahil değil):

  1. sahip olan unsurlar accept yöntem (konvansiyonel olarak yöntemi adlandırıyoruz "accept")
  2. Tanımlayan ziyaretçiler visit yöntem. Bu, mantıklarını ilgilendikleri öğeler üzerinde çalıştırdıkları yerdir.

uygulayan nesneler visit yöntem almak element (veya daha resmi olarak düğüm) bir argüman olarak söz konusu. Bu sırada ziyaretçi, ilgi duyduğu nesnelere istediği mantığı gerçekleştirebilir.

Bir kütüphane yazıyor olsaydık ve ona sahip olacak bir Ziyaretçi sağlarsak visit bir geçiş (veya bir döngü işlemi) sırasında çağrılan yöntem, bu çağrı aracılığıyla istemcilere bir tür genişletilebilirliği kolayca uygulayabiliriz.

Örneğin, bu öğe koleksiyonuna sahip olduğumuzu varsayalım (bunlar DOM düğümler–ancak gerçek DOM düğümleri değildir):

[
  { "tagName": "div", "style": { "width": "28.5px", "height": "20px" } },
  { "tagName": "label", "style": { "width": "28.5px", "height": "20px" } },
  {
    "tagName": "div",
    "style": { "width": "28.5px", "height": "20px" },
    "children": [
      {
        "tagName": "div",
        "style": { "width": "28.5px", "height": "20px" },
        "children": [
          {
            "tagName": "input",
            "style": { "width": "28.5px", "height": "20px" }
          },
          {
            "tagName": "input",
            "style": { "width": "28.5px", "height": "20px" }
          },
          {
            "tagName": "select",
            "style": { "width": "28.5px", "height": "20px" }
          },
          {
            "tagName": "div",
            "style": { "width": "28.5px", "height": "20px" },
            "children": [
              {
                "tagName": "input",
                "style": { "width": "28.5px", "height": "20px" }
              },
              {
                "tagName": "div",
                "style": { "width": "28.5px", "height": "20px" },
                "children": [
                  {
                    "tagName": "a",
                    "href": "https://google.com",
                    "target": "_blank"
                  }
                ]
              },
              {
                "tagName": "select",
                "style": { "width": "28.5px", "height": "20px" }
              }
            ]
          },
          {
            "tagName": "input",
            "style": { "width": "28.5px", "height": "20px" }
          }
        ]
      }
    ]
  }
]

Kodumuzun tüketicilerinin herhangi bir öğe koleksiyonu sağlamasına ve onlara anahtarlarını/değerlerini istedikleri gibi dönüştürebilecek kendi işlevlerini kolayca sağlama yeteneği veren küçük, basit bir JavaScript kitaplığı oluşturduğumuzu varsayalım.

DOM ağacındaki her öğeyi yineleyen ve ilgilendikleri düğümleri manipüle etmek için işlevlerini transformatör olarak geçirmelerine izin veren bir API sağlayabiliriz.

İlk önce tabanımızı tanımlayacağız Node alan sınıf element ve saklar dahili olarak:

class Node {
  constructor(value) {
    this.value = value
  }

  accept(visitor) {
    visitor.visit(this)
  }
}

Bizim Node sınıf tanımlar accept aracılığıyla ziyaretçileri çağıran yöntem visit yöntem. Ek olarak, içinden geçer this argümanlar olarak ziyaretçiler orijinal öğeyi özgürce manipüle edebilir.

Sonra bir üssümüz olacak Visitor gelecekteki tüm ziyaretçilerin katılacağı sınıf türetmek itibaren:

class Visitor {
  visit(node) {}
}

Bu sayede artık ziyaretçi oluşturmaya başlama konumundayız.

Bir ile başlayalım SelectOptionsVisitor ziyaretçi. Bu ziyaretçi ilgilenecek seçme öğeleri ve müşterilerin özel seçenekler belirlemesine izin verin:

class SelectOptionsVisitor extends Visitor {
  constructor(options) {
    super()
    this.options = options
  }

  visit(node) {
    if (node.value.tagName === 'select') {
      node.value.options = this.options.map((option) => ({
        tagName: 'option',
        value: option,
        text: option[0].toUpperCase() + option.slice(1),
      }))
    }
  }
}

İstemci olalım ve bir örneğini oluşturalım. Ziyaretçimizin tüm seçili seçenekleri şu şekilde ayarlamasını sağlayacağız: "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" ve "Sunday":

const selectOptionsVisitor = new SelectOptionsVisitor([
  'Monday',
  'Tuesday',
  'Wednesday',
  'Thursday',
  'Friday',
  'Saturday',
  'Sunday',
])

Şimdi, bazı döngü işlemlerinde geri aramaların her öğeye inmesi için bir yola ihtiyacımız var. gibi kütüphaneler Babil gibi bir şey adında bir yardımcı program sağlayın çapraz Bunu yapmak için.

Her düğümü yineleyecek ve onların adını çağıracak kendi basit traversimiz ile gösterelim accept yöntem:

const traverse = function traverseNodes(elements, visitorsProp) {
  const visitors = []

  if (visitorsProp) {
    ;(Array.isArray(visitorsProp) ? visitorsProp : [visitorsProp]).forEach(
      (visitor) => visitors.push(visitor),
    )
  } else {
    throw new Error(`No visitors to run`)
  }

  const nodes = elements.map((element) => {
    const node = new Node(element)

    for (const visitor of visitors) {
      node.accept(visitor)
      if (node.value.children) {
        traverse(node.value.children, visitors)
      }
    }

    return node
  })

  return {
    [Symbol.for('nodejs.util.inspect.custom')]() {
      return this.toJSON()
    },
    toJSON() {
      return nodes.map((node) => node.value)
    },
    toString() {
      return JSON.stringify(this.toJSON())
    },
  }
}

Şimdi yenimizi kullanalım traverse işlev ve ilk snippet’imizde sahip olduğumuz öğeler listemizi iletin:

const selectOptionsVisitor = new SelectOptionsVisitor([
  'Monday',
  'Tuesday',
  'Wednesday',
  'Thursday',
  'Friday',
  'Saturday',
  'Sunday',
])

const traversed = traverse(elems, [selectOptionsVisitor])

console.log(traversed.toJSON())

şimdi kendimize bakarsak eleman seçhaftanın yedi gününü içerecek şekilde dönüştürüldüğünü fark edeceğiz. options:

Eğer benim gibiyseniz, farklı kalıpları farklı meyvelerle ilişkilendirmek gibi tuhaf bir alışkanlığınız olabilir. Evet, elma ve muz gibi meyveler. Ziyaretçi modelini bir Apple ile ilişkilendiriyorum çünkü tıpkı elmalar gibi pek çok fayda sağlıyorlar, örneğin:

  1. Açık/Kapalı İlke – tarafından düşünüldüğü gibi Robert C.Martin, bu ilke “nesneye yönelik tasarımın en önemli ilkesidir”. Ziyaretçi, geliştiricilerin farklı sınıfların farklı nesneleri ile çalışabilecekleri yeni davranışlar tanıtmalarına olanak tanır. uygulamalarını değiştirmeden.
  2. Tek Sorumluluk – Aynı davranışın birden fazla versiyonunu aynı sınıfa taşıyabilirsiniz. Ziyaretçiler mantıklarını doğrudan dışarıdan erişilemeyen bir blokta uyguladıkları için, tek bir hedefe odaklanmalarını sağlamak kolaydır.
  3. Ziyaretçiler çeşitli nesnelerle çalışırken, karmaşık ağaç yapılarıyla çalışırken çok kullanışlı olabilecek çok yararlı bilgiler toplayabilirler. bu YAML JavaScript kitaplığı, zaman uyumsuz desteğiyle bunu daha da ileri götürür.

Dikkat Edilmesi Gerekenler

  • Ziyaretçiler ağaca yeni düğümler eklediğinde veya kaldırdığında tüm ziyaretçileri güncellemeleri gerekir, aksi takdirde hatalara neden olurlar.

  • Ağaçla çalışan sınıflar, accept işlemlerden sonra ziyaretçi artık onlar için çalışmayacaktır.

  • Çoğu kitaplık bu düğümleri değişmez nesneler olarak uygulamaz, bu nedenle herhangi bir yan etkiler!

  • ziyaretçi gerekir asla farkında olma düğümlerin ağaç yapısı. Öğelerin, temel öğelerinden herhangi birinde (örneğin çocuklar) ziyaretçileri aramasına izin verilmelidir.

Diğer desenlerle karşılaştırmalar

Komut Tasarım Modeli

javascript'te komut-tasarım-desen-içi

Ziyaretçiler ilgilendikleri belirli nesneler üzerinde işlem yapabildikleri için gönderici olarak görülebilirler “komutlar” nesneye veya sınıfa bağlı olarak tetiklenir.

Kompozit Tasarım Deseni

javascript'te kompozit-tasarım-kalıp-kalıp

Ağaç yapıları ile çalışırken (bir Soyut Sözdizimi Ağacı örneğin) istemci kodunun tüm nesnelerle çalışabilmesi için genellikle bileşik yapılar olarak uygulanırlar. Ziyaretçi kalıbı benzer bir amacı paylaşır, bu nedenle ziyaretçi ve bileşik kalıbı birleştirmek güçlü bir uygulamadır.

Yineleyici Tasarım Modeli

yineleyici-tasarım-kalıp

Diğer bir güçlü kombinasyon, yineleyici ve ziyaretçi modelinin bir arada olmasıdır. Yineleyici desende, genellikle her nesneyi yinelemek için kendi algoritmalarını enjekte etmek için istemciye maruz kalan bir arabirim vardır. Bu yaklaşımın, herhangi bir alt ağacın çocuklarına derinlemesine erişebilmek gibi bazı sınırlamaları vardır.

Ziyaretçi kalıbı bu boşluğu özyineleme ile doldurmaya yardımcı olabilir, bu yüzden çok güçlüdür. Tıklamak burada örneğini görmek için

Çözüm

Ve bu, bu noktanın sonunu tamamlıyor! Umarım bunu değerli bulmuşsunuzdur ve gelecekte daha fazlasını ararsınız!

İlgili Makaleler

Bir cevap yazın

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

Göz Atın
Kapalı
Başa dön tuşu