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.
Các mẫu thiết kế có thể được phân loại thành ba nhóm chính:
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.
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.
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.
Dưới đây là danh sách một số mẫu thiết kế phổ biến trong mỗi danh mục:
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.
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.
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.
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.
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.
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 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.
// 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.
Mẫu Singleton rất hữu ích trong nhiều tình huống khác nhau, bao gồm:
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.
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.
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.
// 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ẫ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.
// 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:
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.
// 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 đủ.
Mẫu Builder có lợi trong nhiều tình huống khác nhau, bao gồm:
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 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.
// 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ả.
Mẫu nguyên mẫu có giá trị trong nhiều tình huống khác nhau, bao gồm:
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:
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.
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.
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:
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:
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ế.
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.
Mẫu bộ điều hợp có giá trị trong nhiều tình huống khác nhau, bao gồm:
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:
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ế.
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.
Mẫu trang trí có giá trị trong nhiều tình huống khác nhau, bao gồm:
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:
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ế.
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.
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.
Mẫu proxy có giá trị trong nhiều tình huống khác nhau, bao gồm:
Khi sử dụng Mẫu proxy, hãy lưu ý những điều sau:
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ế.
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.
Mẫu tổng hợp có giá trị trong nhiều tình huống khác nhau, bao gồm:
Khi làm việc với Mẫu tổng hợp, hãy cân nhắc những điều sau:
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ế.
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.
Mẫu cầu có giá trị trong nhiều tình huống khác nhau, bao gồm:
Khi sử dụng Mẫu cầu, hãy cân nhắc những điều sau:
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ế.
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.
Mẫu Flyweight có giá trị trong nhiều tình huống khác nhau, bao gồm:
Khi sử dụng Mẫu Flyweight, hãy cân nhắc những điều sau:
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ế.
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.
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.
Mẫu Người quan sát có giá trị trong nhiều tình huống khác nhau, bao gồm:
Khi sử dụng Mẫu quan sát, hãy cân nhắc những điều sau:
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ế.
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.
Mẫu chiến lược có giá trị trong nhiều tình huống khác nhau, bao gồm:
Khi sử dụng Mẫu chiến lược, hãy cân nhắc những điều sau:
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ế.
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.
Mẫu lệnh có giá trị trong nhiều tình huống khác nhau, bao gồm:
Khi sử dụng Mẫu Lệnh, hãy cân nhắc những điều sau:
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ế.
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.
State Pattern có giá trị trong nhiều tình huống khác nhau, bao gồm:
Khi sử dụng Mẫu trạng thái, hãy cân nhắc những điều sau:
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ế.
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.
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:
Khi sử dụng Mô hình Chuỗi Trách nhiệm, hãy cân nhắc những điều sau:
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ế.
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.
Mẫu khách truy cập có giá trị trong nhiều tình huống khác nhau, bao gồm:
Khi sử dụng Mẫu khách truy cập, hãy cân nhắc những điều sau:
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 .