JavaScript’teki bağdaştırıcı modeli | sıcak çevrimiçi



  1. JavaScript’teki bağdaştırıcı modeli

Kuşkusuz, bazı GoF tasarım modellerinin JavaScript ile ilgisi sınırlıdır, çünkü bu tasarım modellerinin başlangıçta nesne yönelimli programlama dilleri veya nesne yönelimli programlama paradigması için tarifleri tanımlaması amaçlanmıştır.


Örneğin komut modeli, işlevleri nesne yönelimli nesneler olarak ele almak ve bunları örneğin başka bir işleve (veya nesne bağlamında: yönteme) parametre olarak iletebilmek için kullanılır. Bu “özellik” zaten işlevsel programlama dillerinde programlama paradigmasının bir parçasıdır: işlevler burada “birinci sınıf vatandaşlardır” ve nesneler olarak ele alınabilir, örneğin değişkenler atanabilir, parametre olarak başka bir işleve iletilebilir veya dönüş olarak kullanılabilir değer.

Ancak, aşağıda sunulan bağdaştırıcı modeli gibi diğer tasarım desenleri de JavaScript’te anlamlıdır. Bağdaştırıcı deseninin JavaScript’te kullanılması, özellikle harici kodla, yani üçüncü taraf kitaplıklarla uğraşıyorsanız düşünülmelidir.

Bir zamanlar bir geliştirme ekibi varmış…


İşte kısa, hayali bir örnek: Çeşitli noktalarda HTTP isteklerinin yapılması gereken bir uygulamamız olduğunu varsayalım. Kendimiz bir HTTP istemcisi uygulamak yerine, karşılık gelen bir kitaplık ararız. Ne de olsa, tekerleği her zaman yeniden icat etmemelisiniz. Neyse ki, JavaScript evreninde epeyce kitaplık veya paket var ve aradığımızı çabucak buluyoruz: seçim paket isteğine düşüyor (spoiler: örneğimiz 2018’de başlıyor ve henüz bunun ne olduğunu bilmiyoruz. seçim daha az iyiydi).

Uygulamamızda ne zaman bir HTTP isteği yapmak istersek, bindiririz. request aşağıdaki gibi:

request('Haber', (error, response, body) => {
// usw.
});

Genel olarak 32 yerde yapıyoruz. HTTP isteklerinin çok büyük hayranları olduğumuz için, birkaç hafta sonra sayı 128’e çıkıyor. Bir süre için sorun yoktu, ancak birkaç ay sonra bazı kötü haberler aldık (şimdi 30 Mart 2019): Mikel Rogersbaş geliştirici istek üzerine kitaplığı “eski” olarak işaretler ve gelecekte aktif olarak geliştirilmeyeceğini duyurur. Biraz ileri geri ve birkaç saatlik grup tartışmalarından sonra, kodumuzu başka bir kitaplığa taşımaya karar veriyoruz.


Seçim hızla eksenlere düştü. GitHub’da 82.000’den fazla Stargazer mı var? Bu iyiye işaret. Artık uygulamamızda 128 haneyi ayarlamamız gerektiğini gönülsüzce kabul ediyoruz, ancak bu sefer daha akıllıyız. Ekipten biri itaatkar bir şekilde GoF tasarım modellerinden birini kullanabileceğimizi öne sürüyor. Geçenlerde bir kitapta JavaScript hakkında bir şeyler okudu. Kalıplardan bazıları muhtemelen JavaScript’te de kullanışlıdır. İlk şüphecilikten sonra, teklifi dinleyelim.

JavaScript’teki bağdaştırıcı modeli


İstek veya axios gibi harici kitaplıkları doğrudan kullanmak yerine, uygulamamız içinde geliştirdiğimiz kendi API’mizi tanımlıyoruz. Örneğin, HTTP istemci işlevselliği söz konusu olduğunda, API şöyle görünebilir (evet, bir sınıf biçiminde!). API, yöntemleri, parametreleri, dönüş değerlerini ve bizim durumumuzda bunun söz tabanlı (geri arama tabanlı değil) eşzamansız bir API olduğunu tanımlar. Yani Bağdaştırıcı Kalıbı açısından bu API, uygulamamız içinde (“istemci” olarak) kullandığımız “adaptör” bileşenidir.

class HTTPClient {
constructor() {
// ...
}

async request(url, method, headers, body, config) {
return Promise.reject('Please implement');
}

async get(url, headers, body, config) {
return this.request(url, 'GET', headers, body, config)
}

async post(url, headers, body, config) {
return this.request(url, 'POST', headers, body, config)
}

// ...
}


Bu dahili API’ye ek olarak, harici kitaplık (şimdi: axios) tarafından belirtilen ikinci (harici) API şimdi devreye giriyor. Bağdaştırıcı Kalıbı bağlamında bu API, “Adaptee” bileşenidir. İki API arasındaki bağlantı (yani, “adaptör” ve “adaptee” arasındaki) artık somut bir HTTPClient uygulaması olan “ConcreteAdapter” biçiminde geliyor. Uyarlandığı şekliyle eksenler için, bir uygulama – sadece bir taslak, dikkat edin – şöyle görünür:

import HTTPClient from './HTTPClient';
class AxiosAdapter extends HTTPClient {

constructor(axios) {
this._axios = axios;
}

async request(url, method, headers, body, config) {
// hier Aufruf der "axios"-Bibliothek
// Adaptation der Parameter plus
// Adaptation des Rückgabewertes
}

async get(url, headers, body, config) {
// ...
}

// ...

}


Bağdaştırıcı sınıfının oluşturulmasını, örneğin bir fabrika sınıfının yardımıyla dışsallaştıralım (hey, başka bir GoF modeli!):

import axios from 'axios';
import AxiosAdapter from './AxiosAdapter';
class HTTPClientFactory {

static createHTTPClient() {
return new AxiosAdapter(axios);
}

}


Böylece, uygulamamızda bunun gibi HTTP istemci örnekleri oluşturabiliriz ve harici axios API ile doğrudan hiçbir ilgimiz olmaz:

import HTTPClientFactory from 'my-http-client';
const client = HTTPClientFactory.createHTTPClient();

Bir yıl sonra …


Neredeyse bir yıl sonra -2020’deyiz- meslektaşımızı dinlediğimiz için kendimizi şanslı sayabiliriz. Sınıfımız artık sadece 128 yerde değil, 256 yerde kullanılıyor! Gerçekten artık bunu değiştirmek istemiyoruz.

Bağdaştırıcı şablon planının, HTTP istemci kitaplığını yeniden değiştirme zamanı geldiğinde işe yaradığını da fark ettik: tweet’ler itibaren Matteo Collina kütüphane on bir hakkında bilgi sahibi olduk. Yerel Node.js HTTP istemcisinden iki kat daha hızlı olduğu söyleniyor. Çok iyi görünüyor (özellikle axios dahili olarak yerel HTTP istemcisini kullandığından). Değişmeli miyiz? Tabii neden olmasın?

Bu büyük bir çaba değil. Basitçe yeni bir bağdaştırıcı sınıfı uygulayın (burada yine kabataslak) …

import HTTPClient from './HTTPClient';
class UndiciAdapter extends HTTPClient {

constructor(undici) {
this._undici = undici;
}

async request(url, method, headers, body, config) {
// hier Aufruf der "undici"-Bibliothek
// Adaptation der Parameter plus
// Adaptation des Rückgabewertes
}

async get(url, headers, body, config) {
// ...
}

// ...

}


…fabrika sınıfını özelleştirin…

import undici from 'undici';
import UndiciAdapter from './UndiciAdapter';
class HTTPClientFactory {

static createHTTPClient() {
return new UndiciAdapter(undici);
}

}


… bitti!

Ve eğer axios kütüphanesine geri dönmek istiyorsak fabrikada birkaç satırı değiştirmemiz yeterli.

… Ve hikayeden alınacak ders’


Ekipten biri, “Ama sorunu bir adaptör modeli olmadan çözebilirdik” diyor. evet yapabilirdik. Sadece fonksiyonlarla fonksiyonel olarak her şeyi çözebilirdik. JavaScript dilini bu kadar çok yönlü yapan da budur. Ve evet, sınıf sözdiziminin arkasında Java gibi dillerden bilinen gerçek sınıflar yoktur. Ve evet, JavaScript’te arabirim eksikliği nedeniyle birçok GoF modelinin uygulanması zordur. Ancak, nesne yönelimli düşünme biçimini (modellerde düşünmeyi de) içeren nesne yönelimli programlama paradigmasının, geliştiriciler arasında çok yaygın olduğu ve kodun bu şekilde hızlı bir şekilde ortak bir anlayış yaratılabileceği inkar edilemez.

Bu anlamda harici API’lerin entegrasyonu ile ilgili olarak şunlar söylenebilir:

“Nesne yönelimli veya işlevsel,
Önemli olan onun iyi olması, gerisi önemli değil.”

(ekipte bilinmeyen geliştirici)


()




ana sayfaya



 
Üst