paint-brush
Bạn muốn nắm vững các mẫu thiết kế Javascript? Đây là tất cả mọi thứ bạn cần biết!từ tác giả@alexmerced
4,501 lượt đọc
4,501 lượt đọc

Bạn muốn nắm vững các mẫu thiết kế Javascript? Đây là tất cả mọi thứ bạn cần biết!

từ tác giả Alex Merced41m2024/03/14
Read on Terminal Reader

dài quá đọc không nổi

Khám phá chi tiết về các mẫu thiết kế JavaScript trong hướng dẫn toàn diện này. Cho dù bạn là người mới bắt đầu hay nhà phát triển có kinh nghiệm, hãy nắm vững các kỹ thuật để nâng cao cấu trúc và khả năng bảo trì mã JavaScript của bạn.
featured image - Bạn muốn nắm vững các mẫu thiết kế Javascript? Đây là tất cả mọi thứ bạn cần biết!
Alex Merced HackerNoon profile picture
0-item


Khi nói đến việc viết mã sạch, dễ bảo trì và hiệu quả, các mẫu thiết kế đóng một vai trò quan trọng trong thế giới phát triển phần mềm. Các mẫu thiết kế là các giải pháp có thể tái sử dụng cho các vấn đề phổ biến mà các nhà phát triển gặp phải khi thiết kế và xây dựng hệ thống phần mềm. Chúng cung cấp một cách tiếp cận có cấu trúc để giải quyết các thách thức cụ thể, giúp tạo mã không chỉ mạnh mẽ mà còn dễ hiểu và dễ bảo trì hơn.


Trong Lập trình hướng đối tượng (OOP ), các mẫu thiết kế đóng vai trò là hướng dẫn để cấu trúc mã của bạn theo cách thúc đẩy tính linh hoạt, khả năng sử dụng lại và khả năng mở rộng. Chúng gói gọn các phương pháp hay nhất và nguyên tắc thiết kế đã phát triển và chắt lọc thành các giải pháp đã được chứng minh.


Tổng quan về nội dung

  • Danh mục mẫu thiết kế
  • Các mẫu thiết kế chung
  • Mẫu Singleton trong JavaScript
  • Các mẫu nhà máy và nhà máy trừu tượng trong JavaScript
  • Mẫu trình tạo trong JavaScript
  • Mẫu nguyên mẫu trong JavaScript
  • Mẫu nhóm đối tượng trong JavaScript
  • Mẫu bộ điều hợp trong JavaScript
  • Mẫu trang trí trong JavaScript
  • Mẫu proxy trong JavaScript
  • Mẫu tổng hợp trong JavaScript
  • Mẫu cầu trong JavaScript
  • Mẫu Flyweight trong JavaScript
  • Mẫu quan sát trong JavaScript
  • Mẫu chiến lược trong JavaScript
  • Mẫu lệnh trong JavaScript
  • Mẫu trạng thái trong JavaScript
  • Chuỗi mẫu trách nhiệm trong JavaScript
  • Mẫu khách truy cập trong JavaScript
  • Phần kết luận


Danh mục mẫu thiết kế

Các mẫu thiết kế có thể được phân loại thành ba nhóm chính:

  1. Các mẫu sáng tạo: Các mẫu này tập trung vào các cơ chế tạo đối tượng, cố gắng tạo các đối tượng theo cách phù hợp với tình huống. Chúng trừu tượng hóa quá trình khởi tạo, làm cho nó trở nên linh hoạt và độc lập hơn với hệ thống.


  2. Các mẫu cấu trúc: Các mẫu cấu trúc xử lý thành phần đối tượng, hình thành mối quan hệ giữa các đối tượng để tạo ra các cấu trúc lớn hơn, phức tạp hơn. Chúng giúp xác định cách kết hợp các đối tượng và lớp để tạo thành các cấu trúc mới và cung cấp chức năng mới.


  3. Các mẫu hành vi: Các mẫu hành vi liên quan đến giao tiếp giữa các đối tượng, xác định cách chúng tương tác và phân bổ trách nhiệm. Những mẫu này giúp bạn thiết kế hệ thống trong đó các đối tượng cộng tác theo cách linh hoạt và hiệu quả hơn.


Các mẫu thiết kế chung

Dưới đây là danh sách một số mẫu thiết kế phổ biến trong mỗi danh mục:


Các mẫu sáng tạo

  1. Mẫu Singleton: Đảm bảo rằng một lớp chỉ có một phiên bản và cung cấp một điểm truy cập toàn cầu vào phiên bản đó.
  2. Mẫu phương thức nhà máy: Xác định giao diện để tạo đối tượng nhưng cho phép các lớp con thay đổi loại đối tượng sẽ được tạo.
  3. Mẫu nhà máy trừu tượng: Cung cấp giao diện để tạo họ các đối tượng liên quan hoặc phụ thuộc mà không chỉ định các lớp cụ thể của chúng.
  4. Mẫu xây dựng: Tách việc xây dựng một đối tượng phức tạp khỏi biểu diễn của nó, cho phép cùng một quy trình xây dựng tạo ra các biểu diễn khác nhau.
  5. Mẫu nguyên mẫu: Tạo các đối tượng mới bằng cách sao chép một đối tượng hiện có, được gọi là nguyên mẫu.
  6. Mẫu nhóm đối tượng: Quản lý nhóm các đối tượng có thể tái sử dụng để giảm thiểu chi phí tạo và phá hủy đối tượng.


Mẫu kết cấu

  1. Mẫu bộ điều hợp: Cho phép sử dụng giao diện của một lớp hiện có làm giao diện khác.
  2. Mẫu trang trí: Gắn các trách nhiệm bổ sung cho một đối tượng một cách linh hoạt, cung cấp một giải pháp thay thế linh hoạt cho phân lớp.
  3. Mẫu proxy: Cung cấp một đại diện thay thế hoặc trình giữ chỗ cho một đối tượng khác để kiểm soát quyền truy cập vào nó.
  4. Mẫu tổng hợp: Soạn các đối tượng thành cấu trúc cây để thể hiện hệ thống phân cấp toàn bộ một phần.
  5. Mẫu cầu: Tách sự trừu tượng của một đối tượng khỏi việc thực hiện nó, cho phép cả hai thay đổi độc lập.
  6. Mẫu Flyweight: Giảm thiểu việc sử dụng bộ nhớ hoặc chi phí tính toán bằng cách chia sẻ nhiều nhất có thể với các đối tượng liên quan.


Mẫu hành vi

  1. Mẫu quan sát: Xác định mối quan hệ phụ thuộc một-nhiều giữa các đối tượng, vì vậy khi một đối tượng thay đổi trạng thái, tất cả các đối tượng phụ thuộc của nó sẽ được thông báo và cập nhật tự động.

  2. Mẫu chiến lược: Xác định một nhóm thuật toán, đóng gói từng thuật toán và làm cho chúng có thể hoán đổi cho nhau.

  3. Mẫu lệnh: Đóng gói một yêu cầu dưới dạng một đối tượng, từ đó cho phép tham số hóa các máy khách bằng hàng đợi, yêu cầu và thao tác.

  4. Mẫu trạng thái: Cho phép một đối tượng thay đổi hành vi của nó khi trạng thái bên trong của nó thay đổi, bao bọc hành vi đó trong các lớp riêng biệt.

  5. Chuỗi mô hình trách nhiệm: Chuyển yêu cầu dọc theo một chuỗi trình xử lý, cho phép mỗi trình xử lý quyết định xử lý yêu cầu hoặc chuyển yêu cầu đó cho trình xử lý tiếp theo trong chuỗi.

  6. Mẫu khách truy cập: Điều này thể hiện một thao tác được thực hiện trên các phần tử của cấu trúc đối tượng, cho phép bạn xác định các thao tác mới mà không thay đổi lớp của các phần tử.


Trong blog này, chúng tôi sẽ đi sâu vào từng mẫu thiết kế này, đưa ra giải thích, trường hợp sử dụng trong thế giới thực và ví dụ về mã JavaScript để giúp bạn hiểu và triển khai chúng một cách hiệu quả trong các dự án của mình.


Mẫu Singleton trong JavaScript

Mẫu Singleton là một mẫu thiết kế sáng tạo nhằm đảm bảo một lớp chỉ có một phiên bản và cung cấp một điểm truy cập toàn cầu vào phiên bản đó. Mẫu này đặc biệt hữu ích khi bạn muốn giới hạn số lượng phiên bản của một lớp trong ứng dụng của mình và kiểm soát quyền truy cập vào một phiên bản được chia sẻ duy nhất.


Trong JavaScript, việc triển khai Mẫu Singleton tương đối đơn giản nhờ tính linh hoạt của ngôn ngữ. Hãy đi sâu vào một ví dụ đơn giản về cách tạo Singleton trong JavaScript.

Ví dụ triển khai

 // Singleton instance let instance = null;
 class Singleton { constructor() { if (!instance) { instance = this; // Your initialization code here } else { return instance; } } // Your methods and properties here }// Usage const singletonA = new Singleton(); const singletonB = new Singleton(); console.log(singletonA === singletonB); // Output: true (both variables reference the same instance)

Trong ví dụ này, chúng ta tạo một lớp Singleton với một hàm tạo để kiểm tra xem một phiên bản đã tồn tại chưa. Nếu một thể hiện không tồn tại, nó sẽ tạo một thể hiện và gán nó cho biến thể hiện. Các lệnh gọi tiếp theo tới hàm tạo sẽ trả về phiên bản hiện có, đảm bảo rằng chỉ có một phiên bản của lớp Singleton.


Các trường hợp sử dụng trong thế giới thực

Mẫu Singleton rất hữu ích trong nhiều tình huống khác nhau, bao gồm:


  • Quản lý cài đặt cấu hình: Bạn có thể sử dụng Singleton để quản lý cài đặt cấu hình cho ứng dụng của mình, đảm bảo rằng có một nguồn đáng tin cậy duy nhất cho các giá trị cấu hình.
  • Trình ghi nhật ký và xử lý lỗi: Singleton có thể được sử dụng để duy trì cơ chế xử lý lỗi hoặc ghi nhật ký tập trung, cho phép bạn hợp nhất các mục nhật ký hoặc thông báo lỗi.
  • Kết nối cơ sở dữ liệu: Khi xử lý cơ sở dữ liệu, bạn có thể muốn sử dụng Singleton để đảm bảo rằng chỉ có một kết nối cơ sở dữ liệu được chia sẻ trên ứng dụng nhằm giảm thiểu mức tiêu thụ tài nguyên.
  • Bộ nhớ đệm: Việc triển khai Singleton để lưu vào bộ nhớ đệm dữ liệu được sử dụng thường xuyên có thể giúp tối ưu hóa hiệu suất bằng cách duy trì một phiên bản bộ nhớ đệm duy nhất.


Cân nhắc

Mặc dù Mẫu Singleton có thể có lợi nhưng điều cần thiết là phải sử dụng nó một cách thận trọng. Việc lạm dụng mẫu Singleton có thể dẫn đến mã được liên kết chặt chẽ và trạng thái toàn cục, điều này có thể khiến ứng dụng của bạn khó bảo trì và kiểm tra hơn. Do đó, điều quan trọng là phải cân nhắc ưu và nhược điểm và áp dụng mẫu mà nó thực sự tăng thêm giá trị cho cơ sở mã của bạn.


Các mẫu nhà máy và nhà máy trừu tượng trong JavaScript

Mẫu nhà máy và Mẫu nhà máy trừu tượng là các mẫu thiết kế sáng tạo liên quan đến việc tạo ra các đối tượng, nhưng chúng thực hiện theo những cách khác nhau và phục vụ các mục đích riêng biệt. Hãy cùng khám phá từng mẫu này và xem cách chúng có thể được triển khai trong JavaScript.


Mẫu nhà máy

Factory Pattern là một mẫu sáng tạo cung cấp giao diện để tạo các đối tượng nhưng cho phép các lớp con thay đổi loại đối tượng sẽ được tạo. Nó đóng gói quá trình tạo đối tượng, làm cho nó linh hoạt hơn và tách rời khỏi mã máy khách.

Ví dụ triển khai

 // Product class class Product { constructor(name) { this.name = name; } }
 // Factory for creating products class ProductFactory { createProduct(name) { return new Product(name); } }// Usage const factory = new ProductFactory(); const productA = factory.createProduct('Product A'); const productB = factory.createProduct('Product B');console.log(productA.name); // Output: 'Product A' console.log(productB.name); // Output: 'Product B'

Trong ví dụ này, ProductFactory chịu trách nhiệm tạo các phiên bản của lớp Sản phẩm. Nó tóm tắt quá trình tạo, cho phép bạn tạo các loại sản phẩm khác nhau bằng cách mở rộng nhà máy.


Mô Hình Nhà Máy Trừu Tượng

Mẫu nhà máy trừu tượng là một mẫu sáng tạo khác cung cấp giao diện để tạo họ các đối tượng liên quan hoặc phụ thuộc mà không chỉ định các lớp cụ thể của chúng. Nó cho phép bạn tạo các bộ đối tượng hoạt động hài hòa với nhau.


Ví dụ triển khai

 // Abstract Product classes class Button { render() {} }
 class Checkbox { render() {} }// Concrete Product classes class MacButton extends Button { render() { return 'Render Mac button'; } }class MacCheckbox extends Checkbox { render() { return 'Render Mac checkbox'; } }class WindowsButton extends Button { render() { return 'Render Windows button'; } }class WindowsCheckbox extends Checkbox { render() { return 'Render Windows checkbox'; } }// Abstract Factory interface class GUIFactory { createButton() {} createCheckbox() {} }// Concrete Factories class MacFactory extends GUIFactory { createButton() { return new MacButton(); } createCheckbox() { return new MacCheckbox(); } }class WindowsFactory extends GUIFactory { createButton() { return new WindowsButton(); } createCheckbox() { return new WindowsCheckbox(); } }// Usage function createUI(factory) { const button = factory.createButton(); const checkbox = factory.createCheckbox(); return { button, checkbox }; }const macUI = createUI(new MacFactory()); console.log(macUI.button.render()); // Output: 'Render Mac button' console.log(macUI.checkbox.render()); // Output: 'Render Mac checkbox'const windowsUI = createUI(new WindowsFactory()); console.log(windowsUI.button.render()); // Output: 'Render Windows button' console.log(windowsUI.checkbox.render()); // Output: 'Render Windows checkbox'


Trong ví dụ này, chúng tôi có hai nhà máy cụ thể, MacFactory và WindowsFactory, mỗi nhà máy có khả năng tạo một tập hợp các thành phần giao diện người dùng liên quan (nút và hộp kiểm) cho nền tảng tương ứng của chúng. Hàm createUI cho phép bạn tạo giao diện người dùng gắn kết cho một nền tảng cụ thể bằng cách sử dụng nhà máy thích hợp.


Khi nào nên sử dụng mẫu nào:

  • Sử dụng Factory Pattern khi bạn muốn gói gọn quá trình tạo đối tượng và cung cấp giao diện đơn giản để tạo đối tượng với các cách triển khai khác nhau.
  • Sử dụng Mẫu nhà máy trừu tượng khi bạn cần tạo các nhóm đối tượng liên quan hoặc phụ thuộc phải hoạt động cùng nhau. Nó giúp đảm bảo rằng các đối tượng được tạo ra có tính tương thích và gắn kết.


Mẫu trình tạo trong JavaScript

Mẫu Builder là một mẫu thiết kế sáng tạo giúp tách việc xây dựng một đối tượng phức tạp khỏi cách biểu diễn của nó, cho phép cùng một quy trình xây dựng tạo ra các cách biểu diễn khác nhau. Mẫu này đặc biệt hữu ích khi bạn có một đối tượng có số lượng thuộc tính lớn và bạn muốn đơn giản hóa việc tạo các phiên bản trong khi vẫn duy trì tính linh hoạt.

Trong JavaScript, Mẫu trình tạo thường được triển khai bằng cách sử dụng lớp hoặc đối tượng trình tạo hướng dẫn việc xây dựng đối tượng phức tạp theo từng bước. Hãy đi sâu vào một ví dụ để hiểu cách nó hoạt động.


Ví dụ triển khai

 // Product class with multiple properties class Product { constructor() { this.name = ''; this.price = 0; this.color = 'white'; // ... other properties }
 // Additional methods can be defined here }// Builder for creating Product instances class ProductBuilder { constructor() { this.product = new Product(); } setName(name) { this.product.name = name; return this; // Return the builder for method chaining } setPrice(price) { this.product.price = price; return this; } setColor(color) { this.product.color = color; return this; } // Other methods to set additional properties build() { return this.product; // Return the fully constructed product } }// Usage const builder = new ProductBuilder();const productA = builder .setName('Product A') .setPrice(99.99) .setColor('blue') .build();const productB = builder .setName('Product B') .setPrice(49.99) .build();console.log(productA); console.log(productB);


Trong ví dụ này, chúng ta có một lớp Sản phẩm có nhiều thuộc tính. Lớp ProductBuilder giúp tạo các phiên bản của Sản phẩm bằng cách cung cấp các phương thức để thiết lập từng thuộc tính theo từng bước. Chuỗi phương thức cho phép bạn đặt nhiều thuộc tính một cách trôi chảy và dễ đọc. Cuối cùng, phương thức build trả về phiên bản Product được xây dựng đầy đủ.


Các trường hợp sử dụng trong thế giới thực

Mẫu Builder có lợi trong nhiều tình huống khác nhau, bao gồm:

  • Tạo đối tượng phức tạp: Khi bạn cần tạo các đối tượng có nhiều thuộc tính tùy chọn hoặc có thể định cấu hình, Mẫu xây dựng sẽ đơn giản hóa quá trình xây dựng.
  • Đối tượng bất biến: Trình xây dựng có thể được sử dụng để tạo các đối tượng bất biến, vì bạn có thể đặt thuộc tính trong quá trình xây dựng nhưng ngăn chặn việc sửa đổi sau đó.
  • Trình xây dựng được tham số hóa: Thay vì sử dụng danh sách tham số dài trong hàm tạo, Mẫu trình xây dựng cung cấp một cách tiếp cận rõ ràng hơn và có tổ chức hơn để xây dựng các đối tượng.
  • Đối tượng cấu hình: Khi định cấu hình thư viện hoặc thành phần, người xây dựng có thể giúp tạo và tùy chỉnh các đối tượng cấu hình.


Cân nhắc

Mặc dù Mẫu xây dựng mang lại nhiều lợi ích nhưng điều quan trọng cần lưu ý là nó làm tăng thêm độ phức tạp cho cơ sở mã của bạn, đặc biệt nếu các đối tượng đang được xây dựng tương đối đơn giản. Do đó, điều cần thiết là phải đánh giá xem mức độ phức tạp mà Builder đưa ra có phù hợp với trường hợp sử dụng cụ thể của bạn hay không.


Mẫu nguyên mẫu trong JavaScript

Mẫu nguyên mẫu là một mẫu thiết kế sáng tạo cho phép bạn tạo các đối tượng mới bằng cách sao chép một đối tượng hiện có, được gọi là nguyên mẫu. Nó thúc đẩy việc tạo các đối tượng mà không chỉ định chính xác lớp đối tượng cần tạo. Mẫu này đặc biệt hữu ích khi bạn muốn tạo các phiên bản của các đối tượng phức tạp một cách hiệu quả.


Trong JavaScript, Mẫu nguyên mẫu có liên quan chặt chẽ với thuộc tính prototype tích hợp sẵn và phương thức Object.create() . Hãy khám phá cách triển khai và sử dụng Mẫu nguyên mẫu trong JavaScript.


Ví dụ triển khai

 // Prototype object const vehiclePrototype = { init(make, model) { this.make = make; this.model = model; }, getDetails() { return `${this.make} ${this.model}`; }, };
 // Create new instances using the prototype const car1 = Object.create(vehiclePrototype); car1.init('Toyota', 'Camry');const car2 = Object.create(vehiclePrototype); car2.init('Honda', 'Civic');console.log(car1.getDetails()); // Output: 'Toyota Camry' console.log(car2.getDetails()); // Output: 'Honda Civic'


Trong ví dụ này, chúng ta định nghĩa một đối tượng vehiclePrototype với các phương thức và thuộc tính chung cho tất cả các phương tiện. Chúng tôi sử dụng Object.create() để tạo các phiên bản mới (car1 và car2) dựa trên nguyên mẫu này. Những phiên bản này kế thừa các thuộc tính và phương thức từ nguyên mẫu, cho phép bạn tạo các đối tượng mới có hành vi được chia sẻ một cách hiệu quả.


Các trường hợp sử dụng trong thế giới thực

Mẫu nguyên mẫu có giá trị trong nhiều tình huống khác nhau, bao gồm:

  • Giảm chi phí khởi tạo đối tượng: Khi bạn cần tạo nhiều phiên bản của một đối tượng có cấu trúc tương tự, Mẫu nguyên mẫu sẽ giảm chi phí thiết lập nhiều lần các thuộc tính và phương thức của đối tượng.
  • Nhân bản các đối tượng phức tạp: Nếu bạn có các đối tượng phức tạp với các cấu trúc lồng nhau, Mẫu nguyên mẫu sẽ đơn giản hóa việc tạo các đối tượng tương tự bằng cách sao chép nguyên mẫu.
  • Tạo đối tượng có thể định cấu hình: Khi bạn muốn tạo các đối tượng có cấu hình khác nhau, bạn có thể sử dụng nguyên mẫu để khởi tạo chúng với nhiều cài đặt khác nhau.


Cân nhắc

Mặc dù Mẫu nguyên mẫu rất hữu ích nhưng nó có một số điều cần cân nhắc:

  • Sao chép nông: Theo mặc định, phương thức Object.create() của JavaScript thực hiện một bản sao nông của các thuộc tính. Nếu nguyên mẫu chứa các đối tượng hoặc hàm lồng nhau, chúng sẽ được chia sẻ giữa các phiên bản. Bạn có thể cần thực hiện sao chép sâu nếu cần thiết.
  • Sửa đổi nguyên mẫu: Hãy thận trọng khi sửa đổi các thuộc tính hoặc phương thức trên nguyên mẫu, vì nó có thể ảnh hưởng đến tất cả các phiên bản được tạo từ nó.
  • Khởi tạo: Mẫu nguyên mẫu thường yêu cầu một bước khởi tạo riêng để đặt các thuộc tính dành riêng cho phiên bản, điều này có thể làm tăng thêm độ phức tạp.


Mẫu nhóm đối tượng trong JavaScript

Mẫu nhóm đối tượng là một mẫu thiết kế sáng tạo quản lý một nhóm các đối tượng có thể tái sử dụng để giảm thiểu chi phí tạo và phá hủy đối tượng. Nó đặc biệt hữu ích khi việc tạo và hủy các đối tượng tốn kém hoặc tốn nhiều tài nguyên. Mẫu nhóm đối tượng giúp cải thiện hiệu suất và sử dụng tài nguyên bằng cách tái chế và tái sử dụng các đối tượng thay vì tạo đối tượng mới từ đầu.


Trong JavaScript, bạn có thể triển khai Mẫu nhóm đối tượng bằng cách sử dụng mảng hoặc các lớp quản lý nhóm tùy chỉnh. Hãy cùng khám phá cách hoạt động của mẫu này bằng một ví dụ đơn giản.

Ví dụ triển khai

 class ObjectPool { constructor(maxSize) { this.maxSize = maxSize; this.pool = []; }
 create() { if (this.pool.length < this.maxSize) { // Create a new object and add it to the pool const obj = { /* Your object initialization code here */ }; this.pool.push(obj); return obj; } else { // Pool is full, cannot create more objects console.log('Pool is full. Cannot create more objects.'); return null; } } reuse() { if (this.pool.length > 0) { // Reuse an object from the pool return this.pool.pop(); } else { // Pool is empty, no objects available for reuse console.log('Pool is empty. No objects available for reuse.'); return null; } } release(obj) { // Release an object back to the pool for reuse this.pool.push(obj); } }// Usage const pool = new ObjectPool(5); // Create a pool with a maximum size of 5 objectsconst obj1 = pool.create(); const obj2 = pool.create(); const obj3 = pool.create();pool.release(obj2); // Release obj2 back to the pool for reuseconst obj4 = pool.reuse(); // Reuse an object from the pool (obj2)


Trong ví dụ này, chúng ta tạo một lớp ObjectPool để quản lý một nhóm đối tượng. Phương thức create tạo các đối tượng mới khi nhóm không đầy, phương thức tái sử dụng lấy một đối tượng từ nhóm để sử dụng lại và phương thức phát hành trả về một đối tượng cho nhóm để sử dụng trong tương lai.


Các trường hợp sử dụng trong thế giới thực

Mẫu nhóm đối tượng rất hữu ích trong nhiều tình huống khác nhau, bao gồm:

  • Kết nối cơ sở dữ liệu: Quản lý kết nối cơ sở dữ liệu có thể tốn nhiều tài nguyên. Việc sử dụng nhóm đối tượng có thể giúp tái sử dụng các kết nối, cải thiện hiệu suất và giảm chi phí.
  • Quản lý luồng: Trong môi trường đa luồng, nhóm đối tượng có thể được sử dụng để quản lý các luồng, đặc biệt khi việc tạo luồng tốn kém.
  • Đối tượng sử dụng nhiều tài nguyên: Đối với các đối tượng tiêu tốn một lượng bộ nhớ đáng kể hoặc mất thời gian khởi tạo, Mẫu nhóm đối tượng có thể giảm chi phí tạo và hủy các phiên bản.


Cân nhắc

Mặc dù Mẫu nhóm đối tượng mang lại lợi ích về hiệu suất nhưng điều quan trọng là phải xem xét những điều sau:

  • Quản lý tài nguyên: Quản lý tài nguyên cẩn thận là cần thiết để đảm bảo rằng các đối tượng được trả lại đúng cách cho nhóm sau khi sử dụng.
  • Kích thước nhóm: Việc chọn kích thước nhóm thích hợp là rất quan trọng để cân bằng việc sử dụng tài nguyên và mức tiêu thụ bộ nhớ.
  • An toàn luồng: Trong môi trường đa luồng, bạn cần triển khai các cơ chế đồng bộ hóa phù hợp để đảm bảo an toàn cho luồng.


Mẫu bộ điều hợp trong JavaScript

Mẫu Bộ điều hợp là mẫu thiết kế cấu trúc cho phép các đối tượng có giao diện không tương thích hoạt động cùng nhau. Nó hoạt động như một cầu nối giữa hai giao diện không tương thích, làm cho chúng tương thích mà không thay đổi mã nguồn. Mẫu này đặc biệt hữu ích khi bạn cần tích hợp hoặc sử dụng mã hiện có không hoàn toàn phù hợp với yêu cầu của ứng dụng.


Trong JavaScript, Mẫu bộ điều hợp có thể được triển khai bằng cách sử dụng các lớp hoặc hàm bao bọc hoặc điều chỉnh giao diện không tương thích. Hãy cùng khám phá cách triển khai và sử dụng Mẫu bộ điều hợp trong JavaScript bằng một ví dụ thực tế.


Ví dụ triển khai

Giả sử bạn có một lớp hiện có tên là OldSystem với một phương thức có tên là legacyRequest :

 class OldSystem { legacyRequest() { return 'Data from the legacy system'; } }


Bây giờ, bạn muốn sử dụng hệ thống cũ này trong ứng dụng hiện đại của mình với giao diện khác. Bạn có thể tạo một lớp hoặc hàm bộ điều hợp như thế này:

 class Adapter { constructor(oldSystem) { this.oldSystem = oldSystem; }
 newRequest() { const legacyData = this.oldSystem.legacyRequest(); // Adapt the data or perform any necessary transformations return `Adapted: ${legacyData}`; } }


Bây giờ, bạn có thể sử dụng lớp Adaptor để làm cho hệ thống cũ tương thích với ứng dụng hiện đại của bạn:

 const oldSystem = new OldSystem(); const adapter = new Adapter(oldSystem);
 const result = adapter.newRequest(); console.log(result); // Output: 'Adapted: Data from the legacy system'


Trong ví dụ này, lớp Adaptor bao bọc OldSystem và cung cấp giao diện mới, newRequest, tương thích với ứng dụng hiện đại của bạn.


Các trường hợp sử dụng trong thế giới thực

Mẫu bộ điều hợp có giá trị trong nhiều tình huống khác nhau, bao gồm:

  • Tích hợp mã kế thừa: Khi bạn cần tích hợp các hệ thống hoặc thư viện cũ với cơ sở mã hiện đại, bộ điều hợp có thể giúp thu hẹp khoảng cách giữa hai hệ thống hoặc thư viện đó.
  • Thư viện của bên thứ ba: Khi sử dụng thư viện hoặc API của bên thứ ba có giao diện không tương thích, bộ điều hợp có thể làm cho chúng phù hợp với yêu cầu của ứng dụng của bạn.
  • Kiểm tra: Bộ điều hợp có thể hữu ích trong việc tạo đối tượng mô phỏng hoặc mô phỏng giao diện trong quá trình kiểm tra để tách biệt các phần phụ thuộc.
  • Khả năng tương thích phiên bản: Bộ điều hợp có thể được sử dụng để duy trì khả năng tương thích với các phiên bản API hoặc thư viện khác nhau.


Cân nhắc

Mặc dù Mẫu bộ điều hợp mang lại tính linh hoạt và khả năng tương thích nhưng điều cần thiết là phải xem xét một số điểm:

  • Hiệu suất: Bộ điều hợp có thể gây ra một số chi phí do các lệnh gọi phương thức bổ sung và chuyển đổi dữ liệu. Đo lường và tối ưu hóa khi cần thiết.
  • Khả năng bảo trì: Giữ mã bộ điều hợp sạch sẽ và được ghi chép đầy đủ để đảm bảo rằng các nhà phát triển trong tương lai hiểu mục đích và cách sử dụng bộ điều hợp.
  • Độ phức tạp của giao diện: Hãy thận trọng để không tạo các bộ điều hợp quá phức tạp và cố gắng làm quá nhiều việc. Giữ họ tập trung vào một nhiệm vụ thích ứng cụ thể.


Mẫu trang trí trong JavaScript

Mẫu trang trí là một mẫu thiết kế cấu trúc cho phép bạn thêm các hành vi hoặc trách nhiệm mới vào các đối tượng một cách linh hoạt mà không làm thay đổi mã hiện có của chúng. Đó là một cách mạnh mẽ để mở rộng chức năng của các đối tượng bằng cách gói chúng bằng các đối tượng trang trí. Mẫu này thúc đẩy nguyên tắc “mở để mở rộng nhưng đóng để sửa đổi”, giúp dễ dàng thêm các tính năng mới vào đối tượng mà không thay đổi cách triển khai cốt lõi của chúng.


Trong JavaScript, Mẫu trang trí có thể được triển khai bằng cách sử dụng các lớp và thành phần đối tượng. Hãy cùng khám phá cách triển khai và sử dụng Mẫu trang trí trong JavaScript bằng một ví dụ thực tế.


Ví dụ triển khai

Giả sử bạn có một lớp cơ sở Coffee :

 class Coffee { cost() { return 5; // Base cost of a regular coffee } } Now, you want to add decorators to your coffee to customize it with additional options, such as milk and sugar:
 javascript Copy code class MilkDecorator { constructor(coffee) { this.coffee = coffee; } cost() { return this.coffee.cost() + 2; // Adding the cost of milk } }class SugarDecorator { constructor(coffee) { this.coffee = coffee; } cost() { return this.coffee.cost() + 1; // Adding the cost of sugar } }


Sau đó, bạn có thể tạo các phiên bản cà phê được trang trí như thế này:

 const regularCoffee = new Coffee(); const coffeeWithMilk = new MilkDecorator(regularCoffee); const coffeeWithMilkAndSugar = new SugarDecorator(coffeeWithMilk);
 console.log(regularCoffee.cost()); // Output: 5 console.log(coffeeWithMilk.cost()); // Output: 7 console.log(coffeeWithMilkAndSugar.cost()); // Output: 8


Trong ví dụ này, chúng ta có lớp Coffee đại diện cho cà phê cơ bản. Các lớp MilkDecorator và SugarDecorator là các lớp trang trí bao bọc một đối tượng cà phê và thêm chi phí sữa và đường tương ứng vào chi phí cơ bản.


Các trường hợp sử dụng trong thế giới thực

Mẫu trang trí có giá trị trong nhiều tình huống khác nhau, bao gồm:

  • Mở rộng các lớp: Bạn có thể sử dụng trình trang trí để thêm các tính năng vào các lớp mà không cần sửa đổi mã nguồn của chúng, giúp dễ dàng giới thiệu chức năng mới.
  • Thành phần động: Trình trang trí cho phép thành phần động của các đối tượng trong thời gian chạy, cho phép bạn xây dựng các đối tượng phức tạp từ các thành phần đơn giản.
  • Tùy chỉnh: Bạn có thể tùy chỉnh các đối tượng bằng cách áp dụng các kết hợp trang trí khác nhau, mang lại sự linh hoạt và khả năng cấu hình.
  • Ghi nhật ký và lập hồ sơ: Trình trang trí có thể được sử dụng để ghi nhật ký hoặc lập hồ sơ các cuộc gọi phương thức mà không sửa đổi lớp gốc.


Cân nhắc

Mặc dù Mẫu trang trí rất linh hoạt nhưng điều quan trọng là phải ghi nhớ một số điểm sau:

  • Thứ tự trang trí: Thứ tự bạn áp dụng các trang trí có thể ảnh hưởng đến hành vi cuối cùng, vì vậy hãy chú ý đến trình tự bạn bọc đồ vật.
  • Độ phức tạp: Việc lạm dụng trang trí có thể dẫn đến mã phức tạp và phức tạp, vì vậy hãy cân nhắc kỹ xem liệu trang trí có phải là giải pháp tốt nhất cho trường hợp sử dụng của bạn hay không.
  • Khả năng tương thích giao diện: Đảm bảo rằng người trang trí tuân thủ giao diện hoặc hợp đồng chung để duy trì khả năng tương thích với các đối tượng họ trang trí.


Mẫu proxy trong JavaScript

Mẫu Proxy là một mẫu thiết kế cấu trúc cung cấp một đại diện thay thế hoặc trình giữ chỗ cho một đối tượng khác để kiểm soát quyền truy cập vào nó. Nó hoạt động như một trung gian hoặc trình bao bọc xung quanh đối tượng mục tiêu, cho phép bạn thêm các hành vi bổ sung, kiểm soát quyền truy cập hoặc trì hoãn việc tạo đối tượng. Mẫu proxy hữu ích trong nhiều trường hợp khác nhau, chẳng hạn như triển khai tải từng phần, kiểm soát truy cập và ghi nhật ký.


Trong JavaScript, proxy có thể được tạo bằng cách sử dụng đối tượng Proxy tích hợp. Hãy cùng khám phá cách triển khai và sử dụng Mẫu proxy trong JavaScript bằng các ví dụ thực tế.


Ví dụ triển khai

Tải chậm bằng proxy

Giả sử bạn có một đối tượng sử dụng nhiều tài nguyên và bạn chỉ muốn tải một cách lười biếng khi cần thiết. Bạn có thể sử dụng proxy để đạt được tải chậm:

 class ExpensiveResource { constructor() { console.log('Creating an expensive resource...'); }
 fetchData() { console.log('Fetching data...'); } }class LazyResourceProxy { constructor() { this.resource = null; } fetchData() { if (!this.resource) { this.resource = new ExpensiveResource(); } this.resource.fetchData(); } }// Usage const lazyResource = new LazyResourceProxy(); // The actual resource is created and data is fetched only when needed lazyResource.fetchData();

Trong ví dụ này, LazyResourceProxy hoạt động như một đại diện thay thế cho ExpensiveResource, chỉ tạo tài nguyên thực tế khi phương thức FetchData được gọi lần đầu tiên.


Kiểm soát truy cập bằng Proxy

Bạn cũng có thể sử dụng proxy để kiểm soát quyền truy cập vào các đối tượng và thuộc tính của chúng:

 const user = { username: 'john_doe', password: 'secret123', };
 const userProxy = new Proxy(user, { get(target, property) { if (property === 'password') { throw new Error('Access denied to password.'); } return target[property]; }, });console.log(userProxy.username); // Output: 'john_doe' console.log(userProxy.password); // Throws an error: 'Access denied to password.'

Trong ví dụ này, proxy chặn hoạt động get và hạn chế quyền truy cập vào thuộc tính mật khẩu.


Các trường hợp sử dụng trong thế giới thực

Mẫu proxy có giá trị trong nhiều tình huống khác nhau, bao gồm:

  • Tải chậm: Bạn có thể sử dụng proxy để trì hoãn việc tạo và khởi tạo các đối tượng sử dụng nhiều tài nguyên cho đến khi chúng thực sự cần thiết.
  • Kiểm soát truy cập: Proxy có thể thực thi các chính sách kiểm soát truy cập, cho phép bạn hạn chế hoặc cấp quyền truy cập vào các thuộc tính hoặc phương thức nhất định.
  • Bộ nhớ đệm: Proxy có thể triển khai cơ chế bộ nhớ đệm để cải thiện hiệu suất bằng cách lưu trữ và trả về dữ liệu được lưu trong bộ nhớ đệm thay vì thực hiện các hoạt động tốn kém.
  • Ghi nhật ký và lập hồ sơ: Proxy có thể ghi nhật ký hoặc lập hồ sơ các lệnh gọi phương thức, giúp bạn hiểu rõ hơn về hành vi của các đối tượng.


Cân nhắc

Khi sử dụng Mẫu proxy, hãy lưu ý những điều sau:

  • Chi phí chung: Proxy có thể đưa ra một số chi phí do chặn hoạt động. Hãy chú ý đến ý nghĩa của hiệu suất, đặc biệt là trong mã quan trọng về hiệu suất.
  • Khả năng tương thích: Đảm bảo rằng proxy tuân thủ cùng giao diện với đối tượng mục tiêu để duy trì khả năng tương thích với mã hiện có.
  • Bảo mật: Mặc dù proxy có thể giúp kiểm soát quyền truy cập nhưng không nên coi chúng là biện pháp bảo mật duy nhất. Các biện pháp bảo mật bổ sung có thể cần thiết, đặc biệt là ở phía máy chủ.


Mẫu tổng hợp trong JavaScript

Mẫu tổng hợp là một mẫu thiết kế cấu trúc cho phép bạn kết hợp các đối tượng thành các cấu trúc dạng cây để thể hiện hệ thống phân cấp toàn bộ một phần. Nó cho phép khách hàng xử lý các đối tượng riêng lẻ và các thành phần của đối tượng một cách thống nhất. Mẫu tổng hợp đặc biệt hữu ích khi bạn cần làm việc với các cấu trúc phức tạp được tạo thành từ các đối tượng nhỏ hơn, có liên quan trong khi vẫn duy trì giao diện nhất quán.


Trong JavaScript, bạn có thể triển khai Mẫu tổng hợp bằng cách sử dụng các lớp hoặc đối tượng có chung giao diện, cho phép bạn xây dựng các cấu trúc phân cấp. Hãy cùng khám phá cách triển khai và sử dụng Mẫu tổng hợp trong JavaScript bằng các ví dụ thực tế.


Ví dụ triển khai

Giả sử bạn đang xây dựng một ứng dụng thiết kế đồ họa cần làm việc với cả các hình dạng đơn giản và các hình dạng phức tạp (ví dụ: nhóm). Bạn có thể sử dụng Mẫu tổng hợp để thể hiện hệ thống phân cấp này:

 // Component interface class Graphic { draw() {} }
 // Leaf class (represents simple shapes) class Circle extends Graphic { constructor() { super(); // Circle-specific properties and methods } draw() { // Draw a circle } }// Composite class (represents groups of shapes) class Group extends Graphic { constructor() { super(); this.graphics = []; } add(graphic) { this.graphics.push(graphic); } draw() { // Draw each graphic in the group this.graphics.forEach((graphic) => graphic.draw()); } }// Usage const circle1 = new Circle(); const circle2 = new Circle(); const group = new Group();group.add(circle1); group.add(circle2);group.draw(); // Draws both circles in the group

Trong ví dụ này, lớp Graphic đóng vai trò là giao diện thành phần. Lớp Circle đại diện cho các hình dạng đơn giản, trong khi lớp Group đại diện cho sự kết hợp của các hình dạng. Cả hai lớp Circle và Group đều triển khai phương thức draw, cho phép bạn xử lý chúng một cách thống nhất khi kết xuất.


Các trường hợp sử dụng trong thế giới thực

Mẫu tổng hợp có giá trị trong nhiều tình huống khác nhau, bao gồm:

  • Khung đồ họa và giao diện người dùng: Nó được sử dụng để thể hiện các giao diện người dùng hoặc cảnh đồ họa phức tạp, trong đó bạn cần xử lý các phần tử riêng lẻ và các nhóm phần tử một cách nhất quán.
  • Hệ thống tệp: Mẫu tổng hợp có thể biểu thị các hệ thống tệp phân cấp, trong đó các tệp và thư mục có chung một giao diện.
  • Cơ cấu tổ chức: Nó có thể được sử dụng để mô hình hóa các cơ cấu tổ chức, chẳng hạn như các phòng ban trong công ty hoặc các bộ phận trong trường đại học.
  • Các thành phần lồng nhau: Khi bạn có các thành phần có thể chứa các thành phần khác (ví dụ: một biểu mẫu chứa các trường đầu vào), Mẫu tổng hợp sẽ giúp quản lý cấu trúc.


Cân nhắc

Khi làm việc với Mẫu tổng hợp, hãy cân nhắc những điều sau:

  • Độ phức tạp: Mặc dù mẫu đơn giản hóa việc làm việc với các cấu trúc phức tạp nhưng nó cũng có thể gây ra sự phức tạp, đặc biệt là khi xử lý các hệ thống phân cấp sâu.
  • Giao diện thống nhất: Đảm bảo rằng tất cả các thành phần (lá và vật liệu tổng hợp) chia sẻ một giao diện chung để duy trì tính nhất quán.
  • Hiệu suất: Tùy thuộc vào việc triển khai, việc duyệt qua cấu trúc tổng hợp có thể có tác động đến hiệu suất, vì vậy hãy tối ưu hóa nếu cần.


Mẫu cầu trong JavaScript

Mẫu cầu là một mẫu thiết kế cấu trúc tách biệt sự trừu tượng của một đối tượng khỏi việc thực hiện nó. Nó cho phép bạn tạo cầu nối giữa hai điều này, cho phép chúng thay đổi độc lập. Mẫu này đặc biệt hữu ích khi bạn muốn tránh sự ràng buộc vĩnh viễn giữa sự trừu tượng hóa và việc triển khai nó, làm cho mã của bạn linh hoạt hơn và dễ bảo trì hơn.


Trong JavaScript, Mẫu cầu nối có thể được triển khai bằng cách sử dụng các lớp và đối tượng cung cấp giao diện trừu tượng để trừu tượng hóa và các triển khai cụ thể khác nhau cho các nền tảng hoặc tính năng khác nhau. Hãy cùng khám phá cách triển khai và sử dụng Bridge Pattern trong JavaScript bằng các ví dụ thực tế.


Triển khai ví dụ

Giả sử bạn đang xây dựng một ứng dụng vẽ có thể hiển thị hình dạng trên các nền tảng khác nhau, chẳng hạn như trình duyệt web và thiết bị di động. Bạn có thể sử dụng Mẫu cầu để tách các hình vẽ (trừu tượng) khỏi logic kết xuất (triển khai):

 // Abstraction class Shape { constructor(renderer) { this.renderer = renderer; }
 draw() { // Delegating the drawing to the specific renderer this.renderer.renderShape(this); } }// Implementor interface class Renderer { renderShape(shape) {} }// Concrete Implementors class WebRenderer extends Renderer { renderShape(shape) { console.log(`Drawing on the web: ${shape.constructor.name}`); } }class MobileRenderer extends Renderer { renderShape(shape) { console.log(`Drawing on mobile: ${shape.constructor.name}`); } }// Concrete Abstractions (Shapes) class Circle extends Shape { constructor(renderer) { super(renderer); } }class Square extends Shape { constructor(renderer) { super(renderer); } }// Usage const webRenderer = new WebRenderer(); const mobileRenderer = new MobileRenderer();const circle = new Circle(webRenderer); const square = new Square(mobileRenderer);circle.draw(); // Output: Drawing on the web: Circle square.draw(); // Output: Drawing on mobile: Square


Trong ví dụ này, lớp Shape biểu thị sự trừu tượng hóa (các hình sẽ được vẽ) và lớp Trình kết xuất biểu thị giao diện triển khai (logic kết xuất dành riêng cho nền tảng). Các trình triển khai cụ thể khác nhau (WebRenderer và MobileRenderer) lần lượt cung cấp logic kết xuất cho nền tảng web và thiết bị di động. Các lớp Hình tròn và Hình vuông là các lớp trừu tượng cụ thể biểu diễn các hình dạng.


Các trường hợp sử dụng trong thế giới thực

Mẫu cầu có giá trị trong nhiều tình huống khác nhau, bao gồm:

  • Độc lập nền tảng: Khi bạn muốn đảm bảo rằng việc trừu tượng hóa và triển khai có thể khác nhau một cách độc lập, giúp việc hỗ trợ nhiều nền tảng trở nên dễ dàng hơn.
  • Trình điều khiển cơ sở dữ liệu: Nó có thể được sử dụng trong trình điều khiển cơ sở dữ liệu để tách mã dành riêng cho cơ sở dữ liệu (triển khai) khỏi các hoạt động cơ sở dữ liệu (trừu tượng hóa).
  • Khung GUI: Trong khung giao diện đồ họa người dùng (GUI), Mẫu cầu có thể giúp tách các thành phần giao diện người dùng khỏi hệ thống cửa sổ cơ bản.
  • Trình điều khiển thiết bị: Khi xử lý phần cứng hoặc trình điều khiển thiết bị, mẫu này cho phép bạn tách mã dành riêng cho thiết bị khỏi mã ứng dụng cấp cao hơn.


Cân nhắc

Khi sử dụng Mẫu cầu, hãy cân nhắc những điều sau:

  • Độ phức tạp: Mặc dù mẫu mang lại tính linh hoạt nhưng nó có thể làm tăng độ phức tạp của cơ sở mã của bạn, đặc biệt là khi xử lý nhiều phần trừu tượng và triển khai.
  • Bảo trì: Đảm bảo rằng các phần trừu tượng hóa và triển khai vẫn được đồng bộ hóa khi có thay đổi vì chúng có thể phát triển độc lập.
  • Thiết kế giao diện: Thiết kế các giao diện trừu tượng và triển khai một cách cẩn thận để đảm bảo chúng đáp ứng các yêu cầu của ứng dụng của bạn.


Mẫu Flyweight trong JavaScript

Mẫu Flyweight là mẫu thiết kế cấu trúc nhằm mục đích giảm mức tiêu thụ bộ nhớ và cải thiện hiệu suất bằng cách chia sẻ các phần chung của đối tượng. Nó đạt được điều này bằng cách tách trạng thái nội tại của một đối tượng (được chia sẻ và không thay đổi) khỏi trạng thái bên ngoài của nó (duy nhất và phụ thuộc vào ngữ cảnh). Mẫu này đặc biệt hữu ích khi bạn có một số lượng lớn các đối tượng tương tự và muốn giảm thiểu mức chiếm dụng bộ nhớ.


Trong JavaScript, bạn có thể triển khai Mẫu Flyweight bằng cách sử dụng các lớp hoặc đối tượng để biểu thị trạng thái nội tại được chia sẻ và trạng thái bên ngoài riêng lẻ. Hãy cùng khám phá cách triển khai và sử dụng Mẫu Flyweight trong JavaScript bằng các ví dụ thực tế.


Ví dụ triển khai

Giả sử bạn đang phát triển một trình soạn thảo văn bản cần hiển thị một lượng lớn văn bản. Thay vì tạo một đối tượng riêng cho từng ký tự, bạn có thể sử dụng Flyweight Pattern để chia sẻ các đối tượng ký tự khi chúng có cùng thuộc tính nội tại (ví dụ: phông chữ và kích thước):

 class Character { constructor(char, font, size) { this.char = char; this.font = font; this.size = size; }
 render() { console.log(`Rendering character "${this.char}" in ${this.font}, size ${this.size}`); } }class CharacterFactory { constructor() { this.characters = {}; } getCharacter(char, font, size) { const key = `${char}-${font}-${size}`; if (!this.characters[key]) { this.characters[key] = new Character(char, font, size); } return this.characters[key]; } }// Usage const factory = new CharacterFactory();const charA1 = factory.getCharacter('A', 'Arial', 12); const charA2 = factory.getCharacter('A', 'Arial', 12); const charB = factory.getCharacter('B', 'Times New Roman', 14);charA1.render(); // Output: Rendering character "A" in Arial, size 12 charA2.render(); // Output: Rendering character "A" in Arial, size 12 (shared instance) charB.render(); // Output: Rendering character "B" in Times New Roman, size 14

Trong ví dụ này, lớp Ký tự đại diện cho các ký tự riêng lẻ với các thuộc tính nội tại như chính ký tự đó, phông chữ và kích thước. Lớp CharacterFactory đảm bảo rằng các ký tự có cùng thuộc tính nội tại sẽ được chia sẻ thay vì bị trùng lặp.


Các trường hợp sử dụng trong thế giới thực

Mẫu Flyweight có giá trị trong nhiều tình huống khác nhau, bao gồm:

  • Xử lý văn bản: Khi làm việc với khối lượng văn bản lớn, nó có thể giảm đáng kể mức tiêu thụ bộ nhớ bằng cách chia sẻ các ký tự, phông chữ chung hoặc các thuộc tính khác liên quan đến văn bản.
  • Phát triển trò chơi: Trong phát triển trò chơi, nó được sử dụng để tối ưu hóa việc hiển thị các đối tượng có chung các đặc điểm nhất định, chẳng hạn như kết cấu hoặc vật liệu.
  • Giao diện người dùng (UI): Nó có thể được áp dụng cho các thành phần UI có kiểu, phông chữ hoặc biểu tượng được chia sẻ để giảm thiểu việc sử dụng tài nguyên.
  • Bộ nhớ đệm: Mẫu này có thể được sử dụng để lưu vào bộ đệm các đối tượng hoặc dữ liệu được sử dụng thường xuyên để cải thiện hiệu suất.


Cân nhắc

Khi sử dụng Mẫu Flyweight, hãy cân nhắc những điều sau:

  • Xác định trạng thái bên trong: Cẩn thận xác định và tách biệt trạng thái bên trong với trạng thái bên ngoài của đối tượng. Trạng thái bên trong nên được chia sẻ, trong khi trạng thái bên ngoài có thể khác nhau.
  • An toàn luồng: Nếu ứng dụng của bạn đa luồng, hãy đảm bảo rằng các đối tượng Flyweight an toàn theo luồng.
  • Bộ nhớ so với hiệu suất: Mặc dù Mẫu Flyweight giảm mức sử dụng bộ nhớ nhưng nó có thể gây ra hao phí hiệu năng một chút do nhu cầu tra cứu và phiên bản dùng chung.


Mẫu quan sát trong JavaScript

Mẫu quan sát là mẫu thiết kế hành vi thiết lập sự phụ thuộc một-nhiều giữa các đối tượng. Nó cho phép một đối tượng (chủ thể hoặc có thể quan sát được) thông báo cho nhiều người quan sát (người nghe) về những thay đổi về trạng thái hoặc dữ liệu của nó. Mẫu này thường được sử dụng để triển khai các hệ thống xử lý sự kiện phân tán, trong đó trạng thái của một đối tượng thay đổi sẽ kích hoạt các hành động trong các đối tượng phụ thuộc khác.

Trong JavaScript, bạn có thể triển khai Mẫu quan sát bằng cách sử dụng các lớp tùy chỉnh hoặc các tính năng tích hợp sẵn như trình xử lý sự kiện và phương thức addEventListener . Hãy cùng khám phá cách triển khai và sử dụng Mẫu quan sát trong JavaScript bằng các ví dụ thực tế.


Ví dụ triển khai

Mẫu quan sát tùy chỉnh

Giả sử bạn đang xây dựng một ứng dụng thời tiết và bạn muốn các phần khác nhau của giao diện người dùng cập nhật khi điều kiện thời tiết thay đổi. Bạn có thể sử dụng cách triển khai tùy chỉnh của Mẫu quan sát:

 class WeatherStation { constructor() { this.observers = []; }
 addObserver(observer) { this.observers.push(observer); } removeObserver(observer) { const index = this.observers.indexOf(observer); if (index !== -1) { this.observers.splice(index, 1); } } notifyObservers() { this.observers.forEach((observer) => { observer.update(this); }); } setWeatherData(weatherData) { this.weatherData = weatherData; this.notifyObservers(); } }class WeatherDisplay { update(weatherStation) { console.log(`Current weather: ${weatherStation.weatherData}`); } }// Usage const weatherStation = new WeatherStation(); const display1 = new WeatherDisplay(); const display2 = new WeatherDisplay();weatherStation.addObserver(display1); weatherStation.addObserver(display2);weatherStation.setWeatherData('Sunny'); // Both displays update with the new weather data

Trong ví dụ này, WeatherStation đóng vai trò là chủ thể thông báo cho người quan sát (hiển thị đối tượng) khi dữ liệu thời tiết thay đổi. Người quan sát đăng ký chủ đề bằng phương thức addObserver và triển khai phương thức cập nhật để phản ứng với các thay đổi.


Sử dụng Trình xử lý sự kiện

JavaScript cũng cung cấp một cách tích hợp để triển khai Mẫu quan sát bằng cách sử dụng trình xử lý sự kiện:

 class NewsPublisher { constructor() { this.subscribers = []; }
 subscribe(subscriber) { this.subscribers.push(subscriber); } unsubscribe(subscriber) { const index = this.subscribers.indexOf(subscriber); if (index !== -1) { this.subscribers.splice(index, 1); } } publishNews(news) { this.subscribers.forEach((subscriber) => { subscriber(news); }); } }// Usage const publisher = new NewsPublisher();const subscriber1 = (news) => { console.log(`Subscriber 1 received news: ${news}`); };const subscriber2 = (news) => { console.log(`Subscriber 2 received news: ${news}`); };publisher.subscribe(subscriber1); publisher.subscribe(subscriber2);publisher.publishNews('Breaking News: Important Announcement');

Trong ví dụ này, NewsPublisher đóng vai trò là chủ đề và người đăng ký (chức năng) được thêm bằng phương thức đăng ký. Phương thức PublishNews thông báo cho người đăng ký bằng cách gọi các hàm của họ kèm theo tin tức.


Các trường hợp sử dụng trong thế giới thực

Mẫu Người quan sát có giá trị trong nhiều tình huống khác nhau, bao gồm:

  • Giao diện người dùng: Triển khai xử lý sự kiện trong giao diện người dùng đồ họa (GUI) trong đó các thành phần UI phản ứng với hành động của người dùng.
  • Hệ thống đăng ký xuất bản: Xây dựng hệ thống đăng ký xuất bản để phân phối tin nhắn hoặc sự kiện cho nhiều người đăng ký.
  • Model-View-Controller (MVC): Tách mô hình (dữ liệu) khỏi chế độ xem (UI) và thông báo cho các chế độ xem về những thay đổi trong mô hình.
  • Xử lý sự kiện tùy chỉnh: Tạo hệ thống hướng sự kiện tùy chỉnh để quản lý các thay đổi và tương tác trạng thái.

Cân nhắc

Khi sử dụng Mẫu quan sát, hãy cân nhắc những điều sau:

  • Quản lý bộ nhớ: Hãy thận trọng về việc rò rỉ bộ nhớ khi người quan sát giữ các tham chiếu đến đối tượng. Đảm bảo loại bỏ đúng cách những người quan sát khi họ không còn cần thiết nữa.
  • Thứ tự thông báo: Thứ tự thông báo cho người quan sát có thể quan trọng trong một số trường hợp. Đảm bảo rằng đơn hàng đáp ứng yêu cầu của ứng dụng của bạn.
  • Xử lý sự kiện: Khi sử dụng các cơ chế xử lý sự kiện tích hợp, hãy lưu ý đến việc truyền bá sự kiện và tạo bọt trong DOM nếu có.


Mẫu chiến lược trong JavaScript

Mẫu chiến lược là một mẫu thiết kế hành vi cho phép bạn xác định một nhóm các thuật toán có thể hoán đổi cho nhau, đóng gói từng thuật toán và làm cho chúng có thể hoán đổi cho nhau. Nó cho phép khách hàng tự động chọn thuật toán thích hợp trong thời gian chạy. Mẫu này thúc đẩy tính linh hoạt và khả năng sử dụng lại bằng cách tách hành vi của thuật toán khỏi bối cảnh sử dụng nó.

Trong JavaScript, bạn có thể triển khai Mẫu chiến lược bằng cách sử dụng các đối tượng hoặc hàm để thể hiện các chiến lược khác nhau và một đối tượng ngữ cảnh có thể chuyển đổi giữa các chiến lược này. Hãy cùng khám phá cách triển khai và sử dụng Mẫu chiến lược trong JavaScript bằng các ví dụ thực tế.


Ví dụ triển khai

Giả sử bạn đang phát triển một ứng dụng thương mại điện tử và muốn tính toán chiết khấu cho các loại khách hàng khác nhau. Bạn có thể sử dụng Mẫu chiến lược để gói gọn các chiến lược giảm giá:

 // Discount Strategies const regularCustomerDiscount = (amount) => amount * 0.1; // 10% discount const premiumCustomerDiscount = (amount) => amount * 0.2; // 20% discount
 // Context class ShoppingCart { constructor(discountStrategy) { this.items = []; this.discountStrategy = discountStrategy; } addItem(item) { this.items.push(item); } calculateTotal() { const subtotal = this.items.reduce((total, item) => total + item.price, 0); return subtotal - this.discountStrategy(subtotal); } }// Usage const regularCustomerCart = new ShoppingCart(regularCustomerDiscount); const premiumCustomerCart = new ShoppingCart(premiumCustomerDiscount);regularCustomerCart.addItem({ name: 'Item 1', price: 50 }); premiumCustomerCart.addItem({ name: 'Item 2', price: 100 });console.log(`Regular Customer Total: $${regularCustomerCart.calculateTotal()}`); // Output: $45 (after 10% discount) console.log(`Premium Customer Total: $${premiumCustomerCart.calculateTotal()}`); // Output: $80 (after 20% discount)

Trong ví dụ này, chúng tôi xác định hai chiến lược giảm giá là các hàm (regularCustomerDiscount và premiumCustomerDiscount). Lớp ShopCart lấy chiến lược giảm giá làm tham số và tính toán tổng giá dựa trên chiến lược đã chọn.


Các trường hợp sử dụng trong thế giới thực

Mẫu chiến lược có giá trị trong nhiều tình huống khác nhau, bao gồm:

  • Lựa chọn thuật toán: Khi bạn cần chọn một thuật toán từ một nhóm thuật toán một cách linh hoạt.
  • Cấu hình và cài đặt: Định cấu hình ứng dụng với các tùy chọn hành vi khác nhau, chẳng hạn như thuật toán sắp xếp hoặc chiến lược lưu trữ dữ liệu.
  • Hành vi có thể tùy chỉnh: Cho phép người dùng tùy chỉnh và mở rộng hành vi của ứng dụng bằng cách cung cấp các chiến lược khác nhau.
  • Thử nghiệm và mô phỏng: Trong thử nghiệm đơn vị, bạn có thể sử dụng Mẫu chiến lược để cung cấp các triển khai mô phỏng các thành phần để thử nghiệm.


Cân nhắc

Khi sử dụng Mẫu chiến lược, hãy cân nhắc những điều sau:

  • Sự tách biệt rõ ràng: Đảm bảo sự tách biệt rõ ràng giữa bối cảnh và chiến lược để duy trì cơ sở mã rõ ràng và có thể bảo trì.
  • Chuyển đổi động: Khả năng chuyển đổi linh hoạt giữa các chiến lược là tính năng chính của mẫu này. Hãy chắc chắn rằng thiết kế của bạn hỗ trợ tính linh hoạt này.
  • Khởi tạo chiến lược: Hãy chú ý đến cách các chiến lược được khởi tạo và chuyển vào ngữ cảnh để đảm bảo rằng chiến lược chính xác được sử dụng.


Mẫu lệnh trong JavaScript

Mẫu lệnh là một mẫu thiết kế hành vi biến một yêu cầu hoặc thao tác đơn giản thành một đối tượng độc lập. Nó cho phép bạn tham số hóa các đối tượng với các yêu cầu khác nhau, trì hoãn hoặc xếp hàng thực hiện yêu cầu và hỗ trợ các hoạt động không thể hoàn tác. Mẫu này tách rời người gửi yêu cầu khỏi người nhận, giúp dễ dàng mở rộng và duy trì mã.


Trong JavaScript, bạn có thể triển khai Mẫu lệnh bằng cách sử dụng các đối tượng hoặc lớp để biểu diễn các lệnh và trình gọi thực thi các lệnh đó. Hãy cùng khám phá cách triển khai và sử dụng Mẫu lệnh trong JavaScript bằng các ví dụ thực tế.


Ví dụ triển khai

Giả sử bạn đang phát triển một ứng dụng điều khiển từ xa cho một ngôi nhà thông minh và bạn muốn tạo ra một cách linh hoạt để điều khiển các thiết bị khác nhau.


Bạn có thể sử dụng Mẫu lệnh:

 // Command interface class Command { execute() {} }
 // Concrete Commands class LightOnCommand extends Command { constructor(light) { super(); this.light = light; } execute() { this.light.turnOn(); } }class LightOffCommand extends Command { constructor(light) { super(); this.light = light; } execute() { this.light.turnOff(); } }// Receiver (Device) class Light { turnOn() { console.log('Light is on.'); } turnOff() { console.log('Light is off.'); } }// Invoker (Remote Control) class RemoteControl { constructor() { this.commands = []; } addCommand(command) { this.commands.push(command); } executeCommands() { this.commands.forEach((command) => { command.execute(); }); } }// Usage const livingRoomLight = new Light(); const kitchenLight = new Light();const livingRoomLightOn = new LightOnCommand(livingRoomLight); const livingRoomLightOff = new LightOffCommand(livingRoomLight); const kitchenLightOn = new LightOnCommand(kitchenLight); const kitchenLightOff = new LightOffCommand(kitchenLight);const remoteControl = new RemoteControl();remoteControl.addCommand(livingRoomLightOn); remoteControl.addCommand(kitchenLightOff);remoteControl.executeCommands(); // Output: "Light is on." (for living room) // Output: "Light is off." (for kitchen)

Trong ví dụ này, Mẫu lệnh được sử dụng để gói gọn các hành động bật và tắt đèn. RemoteControl đóng vai trò là trình kích hoạt và các lệnh cụ thể (ví dụ: LightOnCommand và LightOffCommand) gói gọn các hành động sẽ được thực thi.


Các trường hợp sử dụng trong thế giới thực

Mẫu lệnh có giá trị trong nhiều tình huống khác nhau, bao gồm:

  • Ứng dụng GUI: Nó thường được sử dụng trong giao diện đồ họa người dùng (GUI) để triển khai chức năng hoàn tác và làm lại, trong đó mỗi hành động của người dùng được gói gọn dưới dạng một lệnh.
  • Hệ thống điều khiển từ xa: Trong các ứng dụng điều khiển từ xa dành cho thiết bị thông minh, nó cung cấp một cách linh hoạt để điều khiển các thiết bị khác nhau bằng các lệnh khác nhau.
  • Xử lý hàng loạt: Khi bạn cần xếp hàng và thực hiện một loạt yêu cầu hoặc tác vụ với các thông số hoặc cài đặt khác nhau.
  • Quản lý giao dịch: Trong các hệ thống cơ sở dữ liệu, nó có thể được sử dụng để đóng gói các hoạt động của cơ sở dữ liệu dưới dạng các lệnh, hỗ trợ hành vi giao dịch.


Cân nhắc

Khi sử dụng Mẫu Lệnh, hãy cân nhắc những điều sau:

  • Trừu tượng hóa lệnh: Đảm bảo rằng các lệnh được trừu tượng hóa một cách thích hợp, gói gọn một hành động hoặc thao tác duy nhất.
  • Hoàn tác và Làm lại: Nếu bạn cần chức năng hoàn tác và làm lại, hãy triển khai các cơ chế cần thiết để hỗ trợ các lệnh đảo ngược.
  • Độ phức tạp: Hãy chú ý đến độ phức tạp được tạo ra bằng cách tạo nhiều lớp lệnh, đặc biệt là trong các tình huống có số lượng lớn các lệnh có thể có.


Mẫu trạng thái trong JavaScript

Mẫu trạng thái là mẫu thiết kế hành vi cho phép một đối tượng thay đổi hành vi khi trạng thái bên trong của nó thay đổi. Nó đóng gói các trạng thái thành các lớp riêng biệt và ủy quyền hành vi cho đối tượng trạng thái hiện tại. Mẫu này giúp quản lý các chuyển đổi trạng thái phức tạp và thúc đẩy nguyên tắc “đóng mở”, giúp dễ dàng thêm trạng thái mới mà không cần sửa đổi mã hiện có.


Trong JavaScript, bạn có thể triển khai Mẫu trạng thái bằng cách sử dụng các lớp để thể hiện trạng thái và đối tượng bối cảnh ủy quyền hành vi của nó cho trạng thái hiện tại. Hãy cùng khám phá cách triển khai và sử dụng State Pattern trong JavaScript bằng các ví dụ thực tế.


Ví dụ triển khai

Giả sử bạn đang phát triển một máy bán hàng tự động phân phối các sản phẩm khác nhau. Hoạt động của máy bán hàng tự động phụ thuộc vào trạng thái hiện tại của nó, chẳng hạn như “Sẵn sàng”, “Đang phân phối” hoặc “Đã bán hết”. Bạn có thể sử dụng Mẫu trạng thái để mô hình hóa hành vi này:

 // State interface class VendingMachineState { insertMoney() {} ejectMoney() {} selectProduct() {} dispenseProduct() {} }
 // Concrete States class ReadyState extends VendingMachineState { constructor(machine) { super(); this.machine = machine; } insertMoney() { console.log('Money inserted.'); this.machine.setState(this.machine.getDispensingState()); } selectProduct() { console.log('Please insert money first.'); } }class DispensingState extends VendingMachineState { constructor(machine) { super(); this.machine = machine; } dispenseProduct() { console.log('Product dispensed.'); this.machine.setState(this.machine.getReadyState()); } }class VendingMachine { constructor() { this.readyState = new ReadyState(this); this.dispensingState = new DispensingState(this); this.currentState = this.readyState; } setState(state) { this.currentState = state; } getReadyState() { return this.readyState; } getDispensingState() { return this.dispensingState; } insertMoney() { this.currentState.insertMoney(); } selectProduct() { this.currentState.selectProduct(); } dispenseProduct() { this.currentState.dispenseProduct(); } }// Usage const vendingMachine = new VendingMachine();vendingMachine.selectProduct(); // Output: "Please insert money first." vendingMachine.insertMoney(); // Output: "Money inserted." vendingMachine.dispenseProduct(); // Output: "Product dispensed."

Trong ví dụ này, Mẫu trạng thái được sử dụng để quản lý hoạt động của máy bán hàng tự động. Các trạng thái như “Sẵn sàng” và “Đang phân phối” được biểu diễn dưới dạng các lớp riêng biệt và bối cảnh (máy bán hàng tự động) ủy quyền hành vi của nó cho trạng thái hiện tại.


Các trường hợp sử dụng trong thế giới thực

State Pattern có giá trị trong nhiều tình huống khác nhau, bao gồm:

  • Quản lý quy trình làm việc: Quản lý quy trình làm việc của ứng dụng với các trạng thái và chuyển tiếp khác nhau, chẳng hạn như quy trình xử lý đơn hàng hoặc phê duyệt.
  • Phát triển trò chơi: Triển khai các hành vi của nhân vật trong trò chơi thay đổi dựa trên trạng thái trò chơi, chẳng hạn như “nhàn rỗi”, “tấn công” hoặc “phòng thủ”.
  • Giao diện người dùng (UI): Xử lý hành vi của các thành phần UI dựa trên các tương tác người dùng hoặc trạng thái ứng dụng khác nhau.
  • Máy trạng thái hữu hạn: Triển khai các máy trạng thái hữu hạn để phân tích cú pháp, xác thực hoặc liên lạc mạng.


Cân nhắc

Khi sử dụng Mẫu trạng thái, hãy cân nhắc những điều sau:

  • Chuyển đổi trạng thái: Đảm bảo rằng các chuyển đổi trạng thái được xác định rõ ràng và các trạng thái đó gói gọn hành vi của chúng một cách hiệu quả.
  • Quản lý bối cảnh: Quản lý các chuyển đổi trạng thái của bối cảnh và đảm bảo rằng nó ủy quyền hành vi chính xác cho trạng thái hiện tại.
  • Độ phức tạp: Hãy chú ý đến sự phức tạp có thể phát sinh khi xử lý nhiều trạng thái và chuyển tiếp trong một ứng dụng phức tạp.


Chuỗi mẫu trách nhiệm trong JavaScript

Mẫu Chuỗi trách nhiệm là mẫu thiết kế hành vi giúp bạn xây dựng chuỗi đối tượng để xử lý yêu cầu. Mỗi đối tượng trong chuỗi có cơ hội xử lý yêu cầu hoặc chuyển nó đến đối tượng tiếp theo trong chuỗi. Nó tách riêng người gửi yêu cầu khỏi người nhận và cho phép nhiều trình xử lý nằm trong chuỗi. Mẫu này thúc đẩy tính linh hoạt và khả năng mở rộng bằng cách cho phép bạn thêm hoặc sửa đổi trình xử lý mà không ảnh hưởng đến mã máy khách.


Trong JavaScript, bạn có thể triển khai Mẫu Chuỗi trách nhiệm bằng cách sử dụng các đối tượng hoặc lớp đại diện cho trình xử lý và ứng dụng khách khởi tạo yêu cầu. Mỗi trình xử lý có một tham chiếu đến trình xử lý tiếp theo trong chuỗi. Hãy cùng khám phá cách triển khai và sử dụng Chuỗi trách nhiệm trong JavaScript bằng các ví dụ thực tế.


Triển khai ví dụ

Giả sử bạn đang phát triển một hệ thống xử lý đơn hàng và bạn muốn xử lý các đơn hàng dựa trên tổng số tiền của chúng. Bạn có thể sử dụng Mô hình chuỗi trách nhiệm để tạo một chuỗi người xử lý, mỗi người chịu trách nhiệm xử lý các đơn đặt hàng trong một phạm vi giá nhất định:

 // Handler interface class OrderHandler { constructor() { this.nextHandler = null; }
 setNextHandler(handler) { this.nextHandler = handler; } handleOrder(order) { if (this.canHandleOrder(order)) { this.processOrder(order); } else if (this.nextHandler) { this.nextHandler.handleOrder(order); } else { console.log('No handler can process this order.'); } } canHandleOrder(order) {} processOrder(order) {} }// Concrete Handlers class SmallOrderHandler extends OrderHandler { canHandleOrder(order) { return order.amount <= 100; } processOrder(order) { console.log(`Processing small order for ${order.amount}`); } }class MediumOrderHandler extends OrderHandler { canHandleOrder(order) { return order.amount <= 500; } processOrder(order) { console.log(`Processing medium order for ${order.amount}`); } }class LargeOrderHandler extends OrderHandler { canHandleOrder(order) { return order.amount > 500; } processOrder(order) { console.log(`Processing large order for ${order.amount}`); } }// Client class Order { constructor(amount) { this.amount = amount; } }// Usage const smallOrderHandler = new SmallOrderHandler(); const mediumOrderHandler = new MediumOrderHandler(); const largeOrderHandler = new LargeOrderHandler();smallOrderHandler.setNextHandler(mediumOrderHandler); mediumOrderHandler.setNextHandler(largeOrderHandler);const order1 = new Order(80); const order2 = new Order(250); const order3 = new Order(600);smallOrderHandler.handleOrder(order1); // Output: "Processing small order for 80" smallOrderHandler.handleOrder(order2); // Output: "Processing medium order for 250" smallOrderHandler.handleOrder(order3); // Output: "Processing large order for 600"

Trong ví dụ này, Mô hình Chuỗi Trách nhiệm được sử dụng để xử lý các đơn đặt hàng có số lượng khác nhau. Mỗi trình xử lý như SmallOrderHandler, MediumOrderHandler và LargeOrderHandler đều xác định xem chúng có thể xử lý đơn hàng hay không dựa trên số tiền của đơn hàng. Nếu có thể, họ sẽ xử lý nó; nếu không, họ chuyển lệnh cho người xử lý tiếp theo trong chuỗi.


Các trường hợp sử dụng trong thế giới thực

Mô hình Chuỗi trách nhiệm có giá trị trong nhiều tình huống khác nhau, bao gồm:

  • Xử lý yêu cầu: Quản lý các quy trình xử lý yêu cầu HTTP, trong đó mỗi phần mềm trung gian hoặc trình xử lý có thể xử lý hoặc chuyển tiếp yêu cầu.
  • Ghi nhật ký và xử lý lỗi: Xử lý thông báo tường trình hoặc lỗi theo cách có cấu trúc, trong đó mỗi trình xử lý chịu trách nhiệm về một loại thông báo tường trình hoặc tình trạng lỗi cụ thể.
  • Xử lý sự kiện: Trong các hệ thống hướng sự kiện, bạn có thể sử dụng mẫu này để xử lý các sự kiện có nhiều người đăng ký, trong đó mỗi người đăng ký có thể xử lý hoặc lọc các sự kiện.
  • Ủy quyền và Xác thực: Thực hiện kiểm tra xác thực và ủy quyền theo trình tự, với mỗi trình xử lý xác minh một khía cạnh cụ thể của yêu cầu.


Cân nhắc

Khi sử dụng Mô hình Chuỗi Trách nhiệm, hãy cân nhắc những điều sau:

  • Cấu hình chuỗi: Đảm bảo rằng chuỗi được cấu hình đúng cách, với các trình xử lý được thiết lập theo đúng thứ tự.
  • Trách nhiệm của người xử lý: Mỗi người xử lý phải có trách nhiệm rõ ràng và không được chồng chéo với trách nhiệm của những người xử lý khác.
  • Xử lý mặc định: Bao gồm logic cho các trường hợp không có trình xử lý nào trong chuỗi có thể xử lý yêu cầu.


Mẫu khách truy cập trong JavaScript

Mẫu khách truy cập là mẫu thiết kế hành vi cho phép bạn tách thuật toán khỏi cấu trúc đối tượng mà nó hoạt động. Nó cung cấp một cách để thêm các hoạt động mới vào các đối tượng mà không cần sửa đổi các lớp của chúng, giúp dễ dàng mở rộng chức năng cho các hệ thống phân cấp đối tượng phức tạp. Mẫu này đặc biệt hữu ích khi bạn có một tập hợp các phần tử riêng biệt và muốn thực hiện nhiều thao tác khác nhau trên chúng mà không sửa đổi mã của chúng.


Trong JavaScript, bạn có thể triển khai Mẫu khách truy cập bằng cách sử dụng các hàm hoặc lớp để thể hiện khách truy cập truy cập các phần tử trong cấu trúc đối tượng. Hãy cùng khám phá cách triển khai và sử dụng Mẫu khách truy cập trong JavaScript bằng các ví dụ thực tế.


Ví dụ triển khai

Giả sử bạn đang phát triển một hệ thống quản lý nội dung trong đó bạn có các loại thành phần nội dung khác nhau như bài viết, hình ảnh và video. Bạn muốn thực hiện nhiều thao tác khác nhau, chẳng hạn như hiển thị và xuất, trên các phần tử này mà không sửa đổi lớp của chúng. Bạn có thể sử dụng Mẫu khách truy cập:

 // Element interface class ContentElement { accept(visitor) {} }
 // Concrete Elements class Article extends ContentElement { accept(visitor) { visitor.visitArticle(this); } }class Image extends ContentElement { accept(visitor) { visitor.visitImage(this); } }class Video extends ContentElement { accept(visitor) { visitor.visitVideo(this); } }// Visitor interface class Visitor { visitArticle(article) {} visitImage(image) {} visitVideo(video) {} }// Concrete Visitors class RendererVisitor extends Visitor { visitArticle(article) { console.log(`Rendering article: ${article.title}`); } visitImage(image) { console.log(`Rendering image: ${image.caption}`); } visitVideo(video) { console.log(`Rendering video: ${video.title}`); } }class ExportVisitor extends Visitor { visitArticle(article) { console.log(`Exporting article: ${article.title}`); } visitImage(image) { console.log(`Exporting image: ${image.caption}`); } visitVideo(video) { console.log(`Exporting video: ${video.title}`); } }// Usage const elements = [new Article('Article 1'), new Image('Image 1'), new Video('Video 1')]; const renderer = new RendererVisitor(); const exporter = new ExportVisitor();elements.forEach((element) => { element.accept(renderer); element.accept(exporter); });

Trong ví dụ này, chúng tôi có các thành phần nội dung như Bài viết, Hình ảnh và Video và chúng tôi muốn thực hiện các hoạt động hiển thị và xuất trên chúng mà không sửa đổi các lớp của chúng. Chúng tôi đạt được điều này bằng cách triển khai các lớp khách truy cập như RendererVisitor và XuấtVisitor truy cập các phần tử và thực hiện các thao tác mong muốn.


Các trường hợp sử dụng trong thế giới thực

Mẫu khách truy cập có giá trị trong nhiều tình huống khác nhau, bao gồm:

  • Xử lý tài liệu: Xử lý các thành phần trong tài liệu, chẳng hạn như HTML hoặc XML, nơi những khách truy cập khác nhau có thể thực hiện các hoạt động phân tích cú pháp, kết xuất hoặc chuyển đổi.
  • Thiết kế trình biên dịch: Trong trình biên dịch, khách truy cập có thể duyệt qua và phân tích cây cú pháp trừu tượng (AST) của ngôn ngữ lập trình cho nhiều mục đích khác nhau như kiểm tra kiểu, tối ưu hóa và tạo mã.
  • Cấu trúc dữ liệu: Khi làm việc với các cấu trúc dữ liệu phức tạp như cây hoặc đồ thị, khách truy cập có thể duyệt qua và thao tác cấu trúc hoặc nội dung của dữ liệu.
  • Báo cáo và phân tích: Trong hệ thống báo cáo, khách truy cập có thể tạo báo cáo, thực hiện phân tích dữ liệu hoặc trích xuất thông tin cụ thể từ tập dữ liệu.


Cân nhắc

Khi sử dụng Mẫu khách truy cập, hãy cân nhắc những điều sau:

  • Khả năng mở rộng: Mẫu giúp dễ dàng thêm các hoạt động mới bằng cách tạo các lớp khách truy cập mới mà không sửa đổi các thành phần hiện có.
  • Độ phức tạp: Lưu ý rằng mẫu có thể gây ra độ phức tạp cao hơn, đặc biệt đối với các cấu trúc đối tượng đơn giản.
  • Đóng gói: Đảm bảo rằng các phần tử đóng gói đúng trạng thái của chúng và cung cấp quyền truy cập thông qua các phương thức của khách truy cập.


Phần kết luận

Trong quá trình khám phá toàn diện các mẫu thiết kế trong JavaScript này, chúng tôi đã đào sâu vào nhiều mẫu khác nhau giúp các nhà phát triển có thể tạo mã linh hoạt, dễ bảo trì và hiệu quả. Mỗi mẫu thiết kế giải quyết các vấn đề cụ thể và cung cấp các giải pháp tinh tế cho những thách thức thiết kế phần mềm phổ biến.


Chúng tôi bắt đầu bằng cách tìm hiểu khái niệm cơ bản về các mẫu thiết kế và phân loại chúng thành ba nhóm chính: các mẫu sáng tạo, cấu trúc và hành vi. Trong mỗi danh mục, chúng tôi đã kiểm tra các mẫu thiết kế phổ biến và giới thiệu cách triển khai thực tế của chúng trong JavaScript.


Dưới đây là bản tóm tắt ngắn gọn về các mẫu thiết kế chính mà chúng tôi đã đề cập:

  • Mẫu sáng tạo: Các mẫu này tập trung vào các cơ chế tạo đối tượng, bao gồm Mẫu Singleton để đảm bảo một phiên bản duy nhất của một lớp, Mẫu nhà máy và nhà máy trừu tượng để tạo đối tượng với các nhà máy linh hoạt, Mẫu xây dựng để xây dựng các đối tượng phức tạp từng bước, Mẫu nguyên mẫu để nhân bản các đối tượng và Mẫu nhóm đối tượng để tái sử dụng đối tượng hiệu quả.


  • Các mẫu cấu trúc: Các mẫu này xử lý thành phần đối tượng, cung cấp các cách để xây dựng các cấu trúc phức tạp từ các thành phần đơn giản hơn. Chúng tôi đã khám phá Mẫu bộ điều hợp để điều chỉnh các giao diện, Mẫu trang trí để thêm hành vi vào các đối tượng một cách linh hoạt, Mẫu proxy để kiểm soát quyền truy cập vào các đối tượng, Mẫu tổng hợp để kết hợp các đối tượng thành cấu trúc cây, Mẫu cầu nối để tách sự trừu tượng hóa khỏi quá trình triển khai và Flyweight Mẫu để giảm thiểu mức sử dụng bộ nhớ bằng cách chia sẻ trạng thái chung.


  • Các mẫu hành vi: Những mẫu này liên quan đến sự tương tác và giao tiếp giữa các đối tượng. Chúng tôi đã đề cập đến Mẫu quan sát để triển khai các hệ thống xử lý sự kiện phân tán, Mẫu chiến lược để đóng gói các thuật toán có thể hoán đổi cho nhau, Mẫu lệnh để chuyển các yêu cầu thành các đối tượng độc lập, Mẫu trạng thái để quản lý hành vi của đối tượng dựa trên trạng thái nội bộ, Mẫu Chuỗi trách nhiệm để xây dựng một chuỗi trình xử lý để xử lý các yêu cầu và Mẫu khách truy cập để tách các thuật toán khỏi cấu trúc đối tượng.


Các mẫu thiết kế là những công cụ có giá trị trong bộ công cụ của nhà phát triển, cho phép tạo ra các cơ sở mã có thể mở rộng và bảo trì được. Hiểu và áp dụng các mẫu này trong các dự án JavaScript của bạn cho phép bạn viết phần mềm hiệu quả hơn, dễ thích ứng và mạnh mẽ hơn.


Hãy nhớ rằng các mẫu thiết kế không phải là giải pháp phù hợp cho tất cả mọi người và khả năng áp dụng của chúng phụ thuộc vào các yêu cầu và thách thức cụ thể của dự án của bạn. Hãy cân nhắc kỹ lưỡng khi nào và làm thế nào để áp dụng chúng để đạt được kết quả tốt nhất.


Khi bạn tiếp tục phát triển với tư cách là nhà phát triển JavaScript, việc nắm vững các mẫu thiết kế này sẽ giúp bạn có khả năng giải quyết các thách thức thiết kế phần mềm phức tạp một cách tự tin và sáng tạo. Cho dù bạn đang xây dựng ứng dụng web, công cụ trò chơi hay bất kỳ phần mềm nào khác, các mẫu thiết kế sẽ là đồng minh của bạn trong việc tạo ra mã trang nhã và dễ bảo trì. Chúc mừng mã hóa!


Cũng được xuất bản ở đây .