Pola Desain JavaScript

Penulis materi, terjemahan yang kami terbitkan, mengatakan bahwa ketika memulai sebuah proyek, mereka tidak segera mulai menulis kode. Pertama-tama, mereka menentukan tujuan dan batasan proyek, kemudian mereka mengidentifikasi peluang yang seharusnya dimiliki. Setelah itu, entah mereka segera menulis kode, atau, jika itu adalah proyek yang agak rumit, mereka memilih pola desain yang sesuai yang menjadi dasarnya. Materi ini tentang pola desain JavaScript. Ini dirancang terutama untuk pengembang pemula.



Apa itu pola desain?


Di bidang pengembangan perangkat lunak, pola desain adalah desain arsitektur berulang yang merupakan solusi untuk masalah desain dalam beberapa konteks yang sering terjadi. Pola desain adalah ringkasan dari pengalaman pengembang perangkat lunak profesional. Pola desain dapat dianggap sebagai semacam pola sesuai dengan program mana yang ditulis.

Mengapa pola desain diperlukan?


Banyak programmer berpikir bahwa pola desain hanya buang-buang waktu, atau tidak tahu cara menerapkannya dengan benar. Namun, menggunakan pola yang sesuai dapat membantu menulis kode yang lebih baik dan lebih mudah dipahami, yang, karena kelengkapannya, akan lebih mudah dipelihara.

Yang paling penting di sini, mungkin, adalah bahwa penggunaan pola memberi pengembang perangkat lunak sesuatu seperti kamus istilah terkenal yang sangat berguna, misalnya, ketika menguraikan kode orang lain. Pola mengungkapkan tujuan fragmen tertentu dari program bagi mereka yang mencoba berurusan dengan perangkat proyek.

Sebagai contoh, jika Anda menggunakan pola "Penghias", itu akan segera memberi tahu programmer baru yang datang ke proyek tentang tugas-tugas mana yang dipecahkan oleh sepotong kode tertentu dan mengapa itu diperlukan. Berkat ini, programmer seperti itu akan dapat mencurahkan lebih banyak waktu untuk tugas-tugas praktis yang dipecahkan oleh program, daripada mencoba memahami struktur internalnya.

Sekarang kami telah menemukan apa pola desain dan untuk apa pola itu, kami akan beralih ke pola itu sendiri dan mendeskripsikan implementasinya menggunakan JavaScript.

Pola "Modul"


Modul adalah sepotong kode independen yang dapat diubah tanpa memengaruhi kode proyek lainnya. Modul, di samping itu, memungkinkan menghindari fenomena seperti polusi area visibilitas karena fakta bahwa mereka membuat area visibilitas terpisah untuk variabel yang dinyatakan di dalamnya. Modul yang ditulis untuk satu proyek dapat digunakan kembali dalam proyek lain jika mekanisme mereka bersifat universal dan tidak terikat dengan spesifikasi proyek tertentu.

Modul adalah bagian integral dari setiap aplikasi JavaScript modern. Mereka membantu menjaga kebersihan kode, membantu memisahkan kode menjadi fragmen yang bermakna, dan membantu mengaturnya. JavaScript memiliki banyak cara untuk membuat modul, salah satunya adalah pola "Modul".

Tidak seperti bahasa pemrograman lain, JavaScript tidak memiliki pengubah akses. Artinya, variabel tidak dapat dinyatakan sebagai pribadi atau publik. Akibatnya, pola "Modul" juga digunakan untuk meniru konsep enkapsulasi.

Pola ini menggunakan IIFE (Ekspresi Fungsional Segera Dibawa), penutupan, dan cakupan fungsi untuk meniru konsep ini. Sebagai contoh:

const myModule = (function() {   const privateVariable = 'Hello World';   function privateMethod() {    console.log(privateVariable);  }  return {    publicMethod: function() {      privateMethod();    }  } })(); myModule.publicMethod(); 

Karena kita memiliki IIFE, kode dieksekusi segera dan objek yang dikembalikan oleh ekspresi ditugaskan ke konstanta myModule . Karena adanya penutupan, objek yang dikembalikan memiliki akses ke fungsi dan variabel yang dideklarasikan di dalam IIFE, bahkan setelah IIFE menyelesaikan pekerjaannya.

Akibatnya, variabel dan fungsi yang dideklarasikan di dalam IIFE disembunyikan dari mekanisme yang berada dalam lingkup visibilitas eksternal terhadap mereka. Mereka berubah menjadi entitas pribadi dari konstanta myModule .

Setelah kode ini dieksekusi, myModule akan terlihat seperti ini:

 const myModule = { publicMethod: function() {   privateMethod(); }}; 

Artinya, merujuk pada konstanta ini, Anda bisa memanggil metode publik objek publicMethod() , yang, pada gilirannya, akan memanggil metode privat privateMethod() . Sebagai contoh:

 //  'Hello World' module.publicMethod(); 

Buka Pola Modul


Pola Revealing Module adalah versi yang sedikit ditingkatkan dari pola Module yang diusulkan Christian Heilmann. Masalah dengan pola "Modul" adalah kita harus membuat fungsi publik hanya untuk mengakses fungsi dan variabel pribadi.

Dalam pola ini, kami menetapkan fungsi pribadi ke properti dari objek yang dikembalikan yang ingin kami publikasikan. Itulah sebabnya pola ini disebut "Modul Terbuka". Pertimbangkan sebuah contoh:

 const myRevealingModule = (function() { let privateVar = 'Peter'; const publicVar  = 'Hello World'; function privateFunction() {   console.log('Name: '+ privateVar); } function publicSetName(name) {   privateVar = name; } function publicGetName() {   privateFunction(); } /**    ,     */ return {   setName: publicSetName,   greeting: publicVar,   getName: publicGetName }; })(); myRevealingModule.setName('Mark'); //  Name: Mark myRevealingModule.getName(); 

Menerapkan pola ini memudahkan untuk memahami fungsi dan variabel modul mana yang tersedia untuk umum, yang membantu meningkatkan keterbacaan kode.

Setelah menjalankan IIFE, myRevealingModule terlihat seperti ini:

 const myRevealingModule = { setName: publicSetName, greeting: publicVar, getName: publicGetName }; 

Kita dapat, misalnya, memanggil metode myRevealingModule.setName('Mark') , yang merupakan referensi ke fungsi internal publicSetName . Metode myRevealingModule.getName() mengacu pada fungsi internal publicGetName . Sebagai contoh:

 myRevealingModule.setName('Mark'); //  Name: Mark myRevealingModule.getName(); 

Pertimbangkan keuntungan dari pola "Modul Terbuka" di atas pola "Modul":

  • "Modul terbuka" memungkinkan Anda untuk membuat entitas tersembunyi publik dari modul (dan menyembunyikannya lagi jika perlu), memodifikasi, untuk masing-masing, hanya satu baris dalam objek yang dikembalikan setelah IIFE.
  • Objek yang dikembalikan tidak mengandung definisi fungsi. Segala sesuatu di sebelah kanan nama propertinya didefinisikan dalam IIFE. Ini membantu menjaga kode tetap bersih dan mudah dibaca.

Modul dalam ES6


Sebelum standar ES6 dirilis, JavaScript tidak memiliki alat standar untuk bekerja dengan modul, akibatnya, pengembang harus menggunakan perpustakaan pihak ketiga atau pola "Modul" untuk menerapkan mekanisme yang sesuai. Tetapi dengan munculnya ES6, sistem modul standar muncul dalam JavaScript.

Modul ES6 disimpan dalam file. Satu file hanya dapat berisi satu modul. Segala sesuatu di dalam modul bersifat pribadi secara default. Fungsi, variabel, dan kelas dapat dibuat publik menggunakan kata kunci export . Kode di dalam modul selalu dijalankan dalam mode ketat.

โ– Modul ekspor


Ada dua cara untuk mengekspor fungsi atau variabel yang dideklarasikan dalam modul:

  • Mengekspor dilakukan dengan menambahkan kata kunci export sebelum mendeklarasikan fungsi atau variabel. Sebagai contoh:

     // utils.js export const greeting = 'Hello World'; export function sum(num1, num2) { console.log('Sum:', num1, num2); return num1 + num2; } export function subtract(num1, num2) { console.log('Subtract:', num1, num2); return num1 - num2; } //  -   function privateLog() { console.log('Private Function'); } 
  • Mengekspor dilakukan dengan menambahkan kata kunci export ke akhir kode yang mencantumkan nama fungsi dan variabel yang akan diekspor. Sebagai contoh:

     // utils.js function multiply(num1, num2) { console.log('Multiply:', num1, num2); return num1 * num2; } function divide(num1, num2) { console.log('Divide:', num1, num2); return num1 / num2; } //    function privateLog() { console.log('Private Function'); } export {multiply, divide}; 

โ– modul Impor


Seperti halnya ada dua cara untuk mengekspor, ada dua cara untuk mengimpor modul. Ini dilakukan dengan menggunakan kata kunci import :

  • Impor beberapa item yang dipilih. Sebagai contoh:

     // main.js //     import { sum, multiply } from './utils.js'; console.log(sum(3, 7)); console.log(multiply(3, 7)); 
  • Impor semua yang diekspor modul. Sebagai contoh:

     // main.js //  ,    import * as utils from './utils.js'; console.log(utils.sum(3, 7)); console.log(utils.multiply(3, 7)); 

โ– Alias โ€‹โ€‹untuk entitas yang diekspor dan diimpor


Jika nama fungsi atau variabel yang diekspor ke kode dapat menyebabkan tabrakan, mereka dapat diubah selama ekspor atau selama impor.

Untuk mengganti nama entitas selama ekspor, Anda dapat melakukan ini:

 // utils.js function sum(num1, num2) { console.log('Sum:', num1, num2); return num1 + num2; } function multiply(num1, num2) { console.log('Multiply:', num1, num2); return num1 * num2; } export {sum as add, multiply}; 

Untuk mengganti nama entitas selama impor, konstruksi berikut digunakan:

 // main.js import { add, multiply as mult } from './utils.js'; console.log(add(3, 7)); console.log(mult(3, 7)); 

Pola Singleton


Pola "Singleton" atau "Singleton" adalah objek yang hanya bisa ada dalam satu salinan. Sebagai bagian dari penerapan pola ini, instance kelas baru dibuat jika belum dibuat. Jika instance kelas sudah ada, maka, ketika mencoba mengakses konstruktor, referensi ke objek yang sesuai dikembalikan. Panggilan selanjutnya ke konstruktor akan selalu mengembalikan objek yang sama.

Faktanya, apa yang kita sebut pola "Singleton" selalu ada dalam JavaScript, tetapi mereka menyebutnya bukan "Singleton", tetapi "objek literal". Pertimbangkan sebuah contoh:

 const user = { name: 'Peter', age: 25, job: 'Teacher', greet: function() {   console.log('Hello!'); } }; 

Karena setiap objek dalam JavaScript menempati area memorinya sendiri dan tidak membaginya dengan objek lain, setiap kali kami mengakses variabel user , kami mendapatkan tautan ke objek yang sama.

Pola Singleton dapat diimplementasikan menggunakan fungsi konstruktor. Ini terlihat seperti ini:

 let instance = null; function User(name, age) { if(instance) {   return instance; } instance = this; this.name = name; this.age = age; return instance; } const user1 = new User('Peter', 25); const user2 = new User('Mark', 24); //  true console.log(user1 === user2); 

Ketika fungsi konstruktor dipanggil, itu pertama-tama memeriksa untuk melihat apakah objek instance ada. Jika variabel yang sesuai tidak diinisialisasi, this ditulis sebagai instance . Jika variabel sudah memiliki referensi ke objek, konstruktor hanya mengembalikan instance , yaitu referensi ke objek yang ada.

Pola Singleton dapat diimplementasikan menggunakan pola Module. Sebagai contoh:

 const singleton = (function() { let instance; function User(name, age) {   this.name = name;   this.age = age; } return {   getInstance: function(name, age) {     if(!instance) {       instance = new User(name, age);     }     return instance;   } } })(); const user1 = singleton.getInstance('Peter', 24); const user2 = singleton.getInstance('Mark', 26); // prints true console.log(user1 === user2); 

Di sini kita membuat instance user dengan memanggil metode singleton.getInstance() . Jika instance objek sudah ada, maka metode ini hanya akan mengembalikannya. Jika belum ada objek seperti itu, metode membuat instance baru dengan memanggil fungsi konstruktor User .

Pola pabrik


Pola Pabrik menggunakan apa yang disebut metode pabrik untuk membuat objek. Anda tidak perlu menentukan kelas atau fungsi konstruktor yang digunakan untuk membuat objek.

Pola ini digunakan untuk membuat objek dalam kasus-kasus ketika tidak perlu untuk membuat logika ciptaannya publik. Pola Pabrik dapat digunakan jika Anda perlu membuat objek yang berbeda tergantung pada kondisi tertentu. Sebagai contoh:

 class Car{ constructor(options) {   this.doors = options.doors || 4;   this.state = options.state || 'brand new';   this.color = options.color || 'white'; } } class Truck { constructor(options) {   this.doors = options.doors || 4;   this.state = options.state || 'used';   this.color = options.color || 'black'; } } class VehicleFactory { createVehicle(options) {   if(options.vehicleType === 'car') {     return new Car(options);   } else if(options.vehicleType === 'truck') {     return new Truck(options);     } } } 

Kelas Car dan Truck dibuat di sini, yang menyediakan untuk penggunaan nilai standar tertentu. Mereka digunakan untuk membuat objek car dan truck . Kelas VehicleFactory juga dideklarasikan di sini, yang digunakan untuk membuat objek baru berdasarkan analisis properti vehicleType , diteruskan ke metode yang sesuai dari objek yang dikembalikan dalam objek dengan options . Inilah cara bekerja dengan semua ini:

 const factory = new VehicleFactory(); const car = factory.createVehicle({ vehicleType: 'car', doors: 4, color: 'silver', state: 'Brand New' }); const truck= factory.createVehicle({ vehicleType: 'truck', doors: 2, color: 'white', state: 'used' }); //  Car {doors: 4, state: "Brand New", color: "silver"} console.log(car); //  Truck {doors: 2, state: "used", color: "white"} console.log(truck); 

Objek factory dari kelas VehicleFactory . Setelah itu, Anda dapat membuat objek dari kelas Car atau Truck dengan memanggil metode factory.createVehicle() dan meneruskannya objek options dengan properti vehicleType diatur ke car atau truck .

Pola dekorator


Pola dekorator digunakan untuk memperluas fungsionalitas objek tanpa memodifikasi kelas yang ada atau fungsi konstruktor. Pola ini dapat digunakan untuk menambahkan kemampuan tertentu ke objek tanpa mengubah kode yang bertanggung jawab atas pembuatannya.

Berikut adalah contoh sederhana menggunakan pola ini:

 function Car(name) { this.name = name; //    this.color = 'White'; } //   ,    const tesla= new Car('Tesla Model 3'); //   -    tesla.setColor = function(color) { this.color = color; } tesla.setPrice = function(price) { this.price = price; } tesla.setColor('black'); tesla.setPrice(49000); //  black console.log(tesla.color); 

Mari kita perhatikan contoh praktis penerapan pola ini. Misalkan biaya mobil tergantung pada fitur mereka, pada fungsi tambahan yang tersedia untuk mereka. Tanpa menggunakan pola Dekorator, untuk menggambarkan mobil-mobil ini, kita harus membuat kelas yang berbeda untuk kombinasi berbeda dari fungsi-fungsi tambahan ini, yang masing-masing akan memiliki metode untuk menemukan biaya mobil. Misalnya, mungkin terlihat seperti ini:

 class Car() { } class CarWithAC() { } class CarWithAutoTransmission { } class CarWithPowerLocks { } class CarWithACandPowerLocks { } 

Berkat pola yang dimaksud, Anda dapat membuat Car kelas dasar, yang menjelaskan, katakanlah, mobil dalam konfigurasi dasar, yang biayanya dinyatakan dengan jumlah tetap. Setelah itu, objek standar yang dibuat berdasarkan kelas ini dapat diperluas menggunakan fungsi dekorator. "Mobil" standar yang diproses oleh fungsi ini mendapat peluang baru, yang, selain itu, mempengaruhi harganya. Sebagai contoh, skema ini dapat diimplementasikan sebagai berikut:

 class Car { constructor() { //   this.cost = function() { return 20000; } } } // - function carWithAC(car) { car.hasAC = true; const prevCost = car.cost(); car.cost = function() {   return prevCost + 500; } } // - function carWithAutoTransmission(car) { car.hasAutoTransmission = true;  const prevCost = car.cost(); car.cost = function() {   return prevCost + 2000; } } // - function carWithPowerLocks(car) { car.hasPowerLocks = true; const prevCost = car.cost(); car.cost = function() {   return prevCost + 500; } } 

Di sini kita pertama membuat Car kelas dasar, yang digunakan untuk membuat objek yang mewakili mobil sebagai standar. Kemudian kita membuat beberapa fungsi dekorator yang memungkinkan kita untuk memperluas objek dari kelas dasar Car dengan properti tambahan. Fungsi-fungsi ini mengambil objek yang sesuai sebagai parameter. Setelah itu, kami menambahkan properti baru ke objek, menunjukkan fitur baru apa yang akan dilengkapi dengan mobil, dan mendefinisikan kembali fungsi cost objek, yang sekarang mengembalikan biaya baru mobil. Akibatnya, untuk "melengkapi" mobil konfigurasi standar dengan sesuatu yang baru, kita dapat menggunakan desain berikut:

 const car = new Car(); console.log(car.cost()); carWithAC(car); carWithAutoTransmission(car); carWithPowerLocks(car); 

Setelah itu, Anda dapat mengetahui biaya mobil dalam konfigurasi yang ditingkatkan:

 //       console.log(car.cost()); 

Ringkasan


Pada artikel ini, kami memeriksa beberapa pola desain yang digunakan dalam JavaScript, tetapi, pada kenyataannya, masih ada banyak pola yang dapat digunakan untuk memecahkan berbagai masalah.

Sementara pengetahuan tentang berbagai pola desain penting bagi programmer, penggunaannya yang tepat sama pentingnya. Mengetahui tentang pola dan ruang lingkup aplikasi mereka, programmer, menganalisis tugas sebelum dia, dapat memahami pola apa yang dapat membantu menyelesaikannya.

Pembaca yang budiman! Pola desain apa yang paling sering Anda gunakan?

Source: https://habr.com/ru/post/id427293/


All Articles